source: mainline/kernel/generic/src/console/cmd.c@ df58e44

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since df58e44 was df58e44, checked in by Martin Decky <martin@…>, 15 years ago
  • add support for printing uspace stack traces from kernel console (as a last resort debugging means)
  • change the semantics of waitq_interrupt_sleep() (require threads_lock to be held even before it is called)
  • minor cstyle
  • Property mode set to 100644
File size: 27.7 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 genericconsole
30 * @{
31 */
32
33/**
34 * @file cmd.c
35 * @brief Kernel console command wrappers.
36 *
37 * This file is meant to contain all wrapper functions for
38 * all kconsole commands. The point is in separating
39 * kconsole specific wrappers from kconsole-unaware functions
40 * from other subsystems.
41 */
42
43#include <console/cmd.h>
44#include <console/console.h>
45#include <console/kconsole.h>
46#include <print.h>
47#include <panic.h>
48#include <typedefs.h>
49#include <adt/list.h>
50#include <arch.h>
51#include <config.h>
52#include <func.h>
53#include <str.h>
54#include <macros.h>
55#include <debug.h>
56#include <cpu.h>
57#include <mm/tlb.h>
58#include <arch/mm/tlb.h>
59#include <mm/frame.h>
60#include <main/version.h>
61#include <mm/slab.h>
62#include <proc/scheduler.h>
63#include <proc/thread.h>
64#include <proc/task.h>
65#include <ipc/ipc.h>
66#include <ipc/irq.h>
67#include <ipc/event.h>
68#include <sysinfo/sysinfo.h>
69#include <symtab.h>
70#include <errno.h>
71
72#ifdef CONFIG_TEST
73#include <test.h>
74#endif
75
76/* Data and methods for 'help' command. */
77static int cmd_help(cmd_arg_t *argv);
78static cmd_info_t help_info = {
79 .name = "help",
80 .description = "List supported commands.",
81 .func = cmd_help,
82 .argc = 0
83};
84
85/* Data and methods for 'reboot' command. */
86static int cmd_reboot(cmd_arg_t *argv);
87static cmd_info_t reboot_info = {
88 .name = "reboot",
89 .description = "Reboot system.",
90 .func = cmd_reboot,
91 .argc = 0
92};
93
94/* Data and methods for 'uptime' command. */
95static int cmd_uptime(cmd_arg_t *argv);
96static cmd_info_t uptime_info = {
97 .name = "uptime",
98 .description = "Show system uptime.",
99 .func = cmd_uptime,
100 .argc = 0
101};
102
103/* Data and methods for 'continue' command. */
104static int cmd_continue(cmd_arg_t *argv);
105static cmd_info_t continue_info = {
106 .name = "continue",
107 .description = "Return console back to userspace.",
108 .func = cmd_continue,
109 .argc = 0
110};
111
112#ifdef CONFIG_TEST
113/* Data and methods for 'test' command. */
114static char test_buf[MAX_CMDLINE + 1];
115static int cmd_test(cmd_arg_t *argv);
116static cmd_arg_t test_argv[] = {
117 {
118 .type = ARG_TYPE_STRING_OPTIONAL,
119 .buffer = test_buf,
120 .len = sizeof(test_buf)
121 }
122};
123static cmd_info_t test_info = {
124 .name = "test",
125 .description = "<test> List kernel tests or run a test.",
126 .func = cmd_test,
127 .argc = 1,
128 .argv = test_argv
129};
130
131/* Data and methods for 'bench' command. */
132static int cmd_bench(cmd_arg_t *argv);
133static cmd_arg_t bench_argv[] = {
134 {
135 .type = ARG_TYPE_STRING,
136 .buffer = test_buf,
137 .len = sizeof(test_buf)
138 },
139 {
140 .type = ARG_TYPE_INT,
141 }
142};
143static cmd_info_t bench_info = {
144 .name = "bench",
145 .description = "<test> <count> Run kernel test as benchmark.",
146 .func = cmd_bench,
147 .argc = 2,
148 .argv = bench_argv
149};
150#endif
151
152/* Data and methods for 'description' command. */
153static int cmd_desc(cmd_arg_t *argv);
154static void desc_help(void);
155static char desc_buf[MAX_CMDLINE + 1];
156static cmd_arg_t desc_argv = {
157 .type = ARG_TYPE_STRING,
158 .buffer = desc_buf,
159 .len = sizeof(desc_buf)
160};
161static cmd_info_t desc_info = {
162 .name = "describe",
163 .description = "<command> Describe specified command.",
164 .help = desc_help,
165 .func = cmd_desc,
166 .argc = 1,
167 .argv = &desc_argv
168};
169
170/* Data and methods for 'symaddr' command. */
171static int cmd_symaddr(cmd_arg_t *argv);
172static char symaddr_buf[MAX_CMDLINE + 1];
173static cmd_arg_t symaddr_argv = {
174 .type = ARG_TYPE_STRING,
175 .buffer = symaddr_buf,
176 .len = sizeof(symaddr_buf)
177};
178static cmd_info_t symaddr_info = {
179 .name = "symaddr",
180 .description = "<symbol> Return symbol address.",
181 .func = cmd_symaddr,
182 .argc = 1,
183 .argv = &symaddr_argv
184};
185
186/* Data and methods for 'set4' command. */
187static char set_buf[MAX_CMDLINE + 1];
188static int cmd_set4(cmd_arg_t *argv);
189static cmd_arg_t set4_argv[] = {
190 {
191 .type = ARG_TYPE_STRING,
192 .buffer = set_buf,
193 .len = sizeof(set_buf)
194 },
195 {
196 .type = ARG_TYPE_INT
197 }
198};
199static cmd_info_t set4_info = {
200 .name = "set4",
201 .description = "<addr> <value> Set 4B memory location to a value.",
202 .func = cmd_set4,
203 .argc = 2,
204 .argv = set4_argv
205};
206
207/* Data and methods for 'call0' and 'mcall0' command. */
208static char call0_buf[MAX_CMDLINE + 1];
209static char carg1_buf[MAX_CMDLINE + 1];
210static char carg2_buf[MAX_CMDLINE + 1];
211static char carg3_buf[MAX_CMDLINE + 1];
212
213static int cmd_call0(cmd_arg_t *argv);
214static cmd_arg_t call0_argv = {
215 .type = ARG_TYPE_STRING,
216 .buffer = call0_buf,
217 .len = sizeof(call0_buf)
218};
219static cmd_info_t call0_info = {
220 .name = "call0",
221 .description = "<function> Call function().",
222 .func = cmd_call0,
223 .argc = 1,
224 .argv = &call0_argv
225};
226
227/* Data and methods for 'mcall0' command. */
228static int cmd_mcall0(cmd_arg_t *argv);
229static cmd_arg_t mcall0_argv = {
230 .type = ARG_TYPE_STRING,
231 .buffer = call0_buf,
232 .len = sizeof(call0_buf)
233};
234static cmd_info_t mcall0_info = {
235 .name = "mcall0",
236 .description = "<function> Call function() on each CPU.",
237 .func = cmd_mcall0,
238 .argc = 1,
239 .argv = &mcall0_argv
240};
241
242/* Data and methods for 'call1' command. */
243static int cmd_call1(cmd_arg_t *argv);
244static cmd_arg_t call1_argv[] = {
245 {
246 .type = ARG_TYPE_STRING,
247 .buffer = call0_buf,
248 .len = sizeof(call0_buf)
249 },
250 {
251 .type = ARG_TYPE_VAR,
252 .buffer = carg1_buf,
253 .len = sizeof(carg1_buf)
254 }
255};
256static cmd_info_t call1_info = {
257 .name = "call1",
258 .description = "<function> <arg1> Call function(arg1).",
259 .func = cmd_call1,
260 .argc = 2,
261 .argv = call1_argv
262};
263
264/* Data and methods for 'call2' command. */
265static int cmd_call2(cmd_arg_t *argv);
266static cmd_arg_t call2_argv[] = {
267 {
268 .type = ARG_TYPE_STRING,
269 .buffer = call0_buf,
270 .len = sizeof(call0_buf)
271 },
272 {
273 .type = ARG_TYPE_VAR,
274 .buffer = carg1_buf,
275 .len = sizeof(carg1_buf)
276 },
277 {
278 .type = ARG_TYPE_VAR,
279 .buffer = carg2_buf,
280 .len = sizeof(carg2_buf)
281 }
282};
283static cmd_info_t call2_info = {
284 .name = "call2",
285 .description = "<function> <arg1> <arg2> Call function(arg1, arg2).",
286 .func = cmd_call2,
287 .argc = 3,
288 .argv = call2_argv
289};
290
291/* Data and methods for 'call3' command. */
292static int cmd_call3(cmd_arg_t *argv);
293static cmd_arg_t call3_argv[] = {
294 {
295 .type = ARG_TYPE_STRING,
296 .buffer = call0_buf,
297 .len = sizeof(call0_buf)
298 },
299 {
300 .type = ARG_TYPE_VAR,
301 .buffer = carg1_buf,
302 .len = sizeof(carg1_buf)
303 },
304 {
305 .type = ARG_TYPE_VAR,
306 .buffer = carg2_buf,
307 .len = sizeof(carg2_buf)
308 },
309 {
310 .type = ARG_TYPE_VAR,
311 .buffer = carg3_buf,
312 .len = sizeof(carg3_buf)
313 }
314
315};
316static cmd_info_t call3_info = {
317 .name = "call3",
318 .description = "<function> <arg1> <arg2> <arg3> Call function(arg1, arg2, arg3).",
319 .func = cmd_call3,
320 .argc = 4,
321 .argv = call3_argv
322};
323
324/* Data and methods for 'halt' command. */
325static int cmd_halt(cmd_arg_t *argv);
326static cmd_info_t halt_info = {
327 .name = "halt",
328 .description = "Halt the kernel.",
329 .func = cmd_halt,
330 .argc = 0
331};
332
333/* Data and methods for 'physmem' command. */
334static int cmd_physmem(cmd_arg_t *argv);
335cmd_info_t physmem_info = {
336 .name = "physmem",
337 .description = "Print physical memory configuration.",
338 .help = NULL,
339 .func = cmd_physmem,
340 .argc = 0,
341 .argv = NULL
342};
343
344/* Data and methods for 'tlb' command. */
345static int cmd_tlb(cmd_arg_t *argv);
346cmd_info_t tlb_info = {
347 .name = "tlb",
348 .description = "Print TLB of the current CPU.",
349 .help = NULL,
350 .func = cmd_tlb,
351 .argc = 0,
352 .argv = NULL
353};
354
355static char flag_buf[MAX_CMDLINE + 1];
356
357static int cmd_threads(cmd_arg_t *argv);
358static cmd_arg_t threads_argv = {
359 .type = ARG_TYPE_STRING_OPTIONAL,
360 .buffer = flag_buf,
361 .len = sizeof(flag_buf)
362};
363static cmd_info_t threads_info = {
364 .name = "threads",
365 .description = "List all threads (use -a for additional information).",
366 .func = cmd_threads,
367 .argc = 1,
368 .argv = &threads_argv
369};
370
371static int cmd_tasks(cmd_arg_t *argv);
372static cmd_arg_t tasks_argv = {
373 .type = ARG_TYPE_STRING_OPTIONAL,
374 .buffer = flag_buf,
375 .len = sizeof(flag_buf)
376};
377static cmd_info_t tasks_info = {
378 .name = "tasks",
379 .description = "List all tasks (use -a for additional information).",
380 .func = cmd_tasks,
381 .argc = 1,
382 .argv = &tasks_argv
383};
384
385/* Data and methods for 'btrace' command */
386static int cmd_btrace(cmd_arg_t *argv);
387static cmd_arg_t btrace_argv = {
388 .type = ARG_TYPE_INT,
389};
390static cmd_info_t btrace_info = {
391 .name = "btrace",
392 .description = "<threadid> Show thread stack trace.",
393 .func = cmd_btrace,
394 .argc = 1,
395 .argv = &btrace_argv
396};
397
398static int cmd_sched(cmd_arg_t *argv);
399static cmd_info_t sched_info = {
400 .name = "scheduler",
401 .description = "Show scheduler information.",
402 .func = cmd_sched,
403 .argc = 0
404};
405
406static int cmd_slabs(cmd_arg_t *argv);
407static cmd_info_t slabs_info = {
408 .name = "slabs",
409 .description = "List slab caches.",
410 .func = cmd_slabs,
411 .argc = 0
412};
413
414static int cmd_sysinfo(cmd_arg_t *argv);
415static cmd_info_t sysinfo_info = {
416 .name = "sysinfo",
417 .description = "Dump sysinfo.",
418 .func = cmd_sysinfo,
419 .argc = 0
420};
421
422/* Data and methods for 'zones' command */
423static int cmd_zones(cmd_arg_t *argv);
424static cmd_info_t zones_info = {
425 .name = "zones",
426 .description = "List memory zones.",
427 .func = cmd_zones,
428 .argc = 0
429};
430
431/* Data and methods for 'zone' command */
432static int cmd_zone(cmd_arg_t *argv);
433static cmd_arg_t zone_argv = {
434 .type = ARG_TYPE_INT,
435};
436
437static cmd_info_t zone_info = {
438 .name = "zone",
439 .description = "<zone> Show memory zone structure.",
440 .func = cmd_zone,
441 .argc = 1,
442 .argv = &zone_argv
443};
444
445/* Data and methods for 'ipc' command */
446static int cmd_ipc(cmd_arg_t *argv);
447static cmd_arg_t ipc_argv = {
448 .type = ARG_TYPE_INT,
449};
450static cmd_info_t ipc_info = {
451 .name = "ipc",
452 .description = "<taskid> Show IPC information of a task.",
453 .func = cmd_ipc,
454 .argc = 1,
455 .argv = &ipc_argv
456};
457
458/* Data and methods for 'kill' command */
459static int cmd_kill(cmd_arg_t *argv);
460static cmd_arg_t kill_argv = {
461 .type = ARG_TYPE_INT,
462};
463static cmd_info_t kill_info = {
464 .name = "kill",
465 .description = "<taskid> Kill a task.",
466 .func = cmd_kill,
467 .argc = 1,
468 .argv = &kill_argv
469};
470
471/* Data and methods for 'cpus' command. */
472static int cmd_cpus(cmd_arg_t *argv);
473cmd_info_t cpus_info = {
474 .name = "cpus",
475 .description = "List all processors.",
476 .help = NULL,
477 .func = cmd_cpus,
478 .argc = 0,
479 .argv = NULL
480};
481
482/* Data and methods for 'version' command. */
483static int cmd_version(cmd_arg_t *argv);
484cmd_info_t version_info = {
485 .name = "version",
486 .description = "Print version information.",
487 .help = NULL,
488 .func = cmd_version,
489 .argc = 0,
490 .argv = NULL
491};
492
493static cmd_info_t *basic_commands[] = {
494 &btrace_info,
495 &call0_info,
496 &mcall0_info,
497 &call1_info,
498 &call2_info,
499 &call3_info,
500 &continue_info,
501 &cpus_info,
502 &desc_info,
503 &halt_info,
504 &help_info,
505 &ipc_info,
506 &kill_info,
507 &physmem_info,
508 &reboot_info,
509 &sched_info,
510 &set4_info,
511 &slabs_info,
512 &symaddr_info,
513 &sysinfo_info,
514 &tasks_info,
515 &threads_info,
516 &tlb_info,
517 &uptime_info,
518 &version_info,
519 &zones_info,
520 &zone_info,
521#ifdef CONFIG_TEST
522 &test_info,
523 &bench_info,
524#endif
525 NULL
526};
527
528
529/** Initialize command info structure.
530 *
531 * @param cmd Command info structure.
532 *
533 */
534void cmd_initialize(cmd_info_t *cmd)
535{
536 spinlock_initialize(&cmd->lock, "cmd.lock");
537 link_initialize(&cmd->link);
538}
539
540/** Initialize and register commands. */
541void cmd_init(void)
542{
543 unsigned int i;
544
545 for (i = 0; basic_commands[i]; i++) {
546 cmd_initialize(basic_commands[i]);
547 if (!cmd_register(basic_commands[i]))
548 printf("Cannot register command %s\n", basic_commands[i]->name);
549 }
550}
551
552/** List supported commands.
553 *
554 * @param argv Argument vector.
555 *
556 * @return 0 on failure, 1 on success.
557 */
558int cmd_help(cmd_arg_t *argv)
559{
560 spinlock_lock(&cmd_lock);
561
562 link_t *cur;
563 size_t len = 0;
564 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
565 cmd_info_t *hlp;
566 hlp = list_get_instance(cur, cmd_info_t, link);
567
568 spinlock_lock(&hlp->lock);
569 if (str_length(hlp->name) > len)
570 len = str_length(hlp->name);
571 spinlock_unlock(&hlp->lock);
572 }
573
574 unsigned int _len = (unsigned int) len;
575 if ((_len != len) || (((int) _len) < 0)) {
576 printf("Command length overflow\n");
577 return 1;
578 }
579
580 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
581 cmd_info_t *hlp;
582 hlp = list_get_instance(cur, cmd_info_t, link);
583
584 spinlock_lock(&hlp->lock);
585 printf("%-*s %s\n", _len, hlp->name, hlp->description);
586 spinlock_unlock(&hlp->lock);
587 }
588
589 spinlock_unlock(&cmd_lock);
590
591 return 1;
592}
593
594/** Reboot the system.
595 *
596 * @param argv Argument vector.
597 *
598 * @return 0 on failure, 1 on success.
599 */
600int cmd_reboot(cmd_arg_t *argv)
601{
602 reboot();
603
604 /* Not reached */
605 return 1;
606}
607
608/** Print system uptime information.
609 *
610 * @param argv Argument vector.
611 *
612 * @return 0 on failure, 1 on success.
613 */
614int cmd_uptime(cmd_arg_t *argv)
615{
616 ASSERT(uptime);
617
618 /* This doesn't have to be very accurate */
619 sysarg_t sec = uptime->seconds1;
620
621 printf("Up %" PRIun " days, %" PRIun " hours, %" PRIun " minutes, %" PRIun " seconds\n",
622 sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
623
624 return 1;
625}
626
627/** Describe specified command.
628 *
629 * @param argv Argument vector.
630 *
631 * @return 0 on failure, 1 on success.
632 */
633int cmd_desc(cmd_arg_t *argv)
634{
635 link_t *cur;
636
637 spinlock_lock(&cmd_lock);
638
639 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
640 cmd_info_t *hlp;
641
642 hlp = list_get_instance(cur, cmd_info_t, link);
643 spinlock_lock(&hlp->lock);
644
645 if (str_lcmp(hlp->name, (const char *) argv->buffer, str_length(hlp->name)) == 0) {
646 printf("%s - %s\n", hlp->name, hlp->description);
647 if (hlp->help)
648 hlp->help();
649 spinlock_unlock(&hlp->lock);
650 break;
651 }
652
653 spinlock_unlock(&hlp->lock);
654 }
655
656 spinlock_unlock(&cmd_lock);
657
658 return 1;
659}
660
661/** Search symbol table */
662int cmd_symaddr(cmd_arg_t *argv)
663{
664 symtab_print_search((char *) argv->buffer);
665
666 return 1;
667}
668
669/** Call function with zero parameters */
670int cmd_call0(cmd_arg_t *argv)
671{
672 uintptr_t symaddr;
673 char *symbol;
674 sysarg_t (*fnc)(void);
675 fncptr_t fptr;
676 int rc;
677
678 symbol = (char *) argv->buffer;
679 rc = symtab_addr_lookup(symbol, &symaddr);
680
681 if (rc == ENOENT)
682 printf("Symbol %s not found.\n", symbol);
683 else if (rc == EOVERFLOW) {
684 symtab_print_search(symbol);
685 printf("Duplicate symbol, be more specific.\n");
686 } else if (rc == EOK) {
687 ipl_t ipl;
688
689 ipl = interrupts_disable();
690 fnc = (sysarg_t (*)(void)) arch_construct_function(&fptr,
691 (void *) symaddr, (void *) cmd_call0);
692 printf("Calling %s() (%p)\n", symbol, (void *) symaddr);
693 printf("Result: %#" PRIxn "\n", fnc());
694 interrupts_restore(ipl);
695 } else {
696 printf("No symbol information available.\n");
697 }
698 return 1;
699}
700
701/** Call function with zero parameters on each CPU */
702int cmd_mcall0(cmd_arg_t *argv)
703{
704 /*
705 * For each CPU, create a thread which will
706 * call the function.
707 */
708
709 unsigned int i;
710 for (i = 0; i < config.cpu_count; i++) {
711 if (!cpus[i].active)
712 continue;
713
714 thread_t *thread;
715 if ((thread = thread_create((void (*)(void *)) cmd_call0,
716 (void *) argv, TASK, THREAD_FLAG_WIRED, "call0", false))) {
717 irq_spinlock_lock(&thread->lock, true);
718 thread->cpu = &cpus[i];
719 irq_spinlock_unlock(&thread->lock, true);
720
721 printf("cpu%u: ", i);
722
723 thread_ready(thread);
724 thread_join(thread);
725 thread_detach(thread);
726 } else
727 printf("Unable to create thread for cpu%u\n", i);
728 }
729
730 return 1;
731}
732
733/** Call function with one parameter */
734int cmd_call1(cmd_arg_t *argv)
735{
736 uintptr_t symaddr;
737 char *symbol;
738 sysarg_t (*fnc)(sysarg_t, ...);
739 sysarg_t arg1 = argv[1].intval;
740 fncptr_t fptr;
741 int rc;
742
743 symbol = (char *) argv->buffer;
744 rc = symtab_addr_lookup(symbol, &symaddr);
745
746 if (rc == ENOENT) {
747 printf("Symbol %s not found.\n", symbol);
748 } else if (rc == EOVERFLOW) {
749 symtab_print_search(symbol);
750 printf("Duplicate symbol, be more specific.\n");
751 } else if (rc == EOK) {
752 ipl_t ipl;
753
754 ipl = interrupts_disable();
755 fnc = (sysarg_t (*)(sysarg_t, ...))
756 arch_construct_function(&fptr, (void *) symaddr,
757 (void *) cmd_call1);
758 printf("Calling f(%#" PRIxn "): %p: %s\n", arg1,
759 (void *) symaddr, symbol);
760 printf("Result: %#" PRIxn "\n", fnc(arg1));
761 interrupts_restore(ipl);
762 } else {
763 printf("No symbol information available.\n");
764 }
765
766 return 1;
767}
768
769/** Call function with two parameters */
770int cmd_call2(cmd_arg_t *argv)
771{
772 uintptr_t symaddr;
773 char *symbol;
774 sysarg_t (*fnc)(sysarg_t, sysarg_t, ...);
775 sysarg_t arg1 = argv[1].intval;
776 sysarg_t arg2 = argv[2].intval;
777 fncptr_t fptr;
778 int rc;
779
780 symbol = (char *) argv->buffer;
781 rc = symtab_addr_lookup(symbol, &symaddr);
782
783 if (rc == ENOENT) {
784 printf("Symbol %s not found.\n", symbol);
785 } else if (rc == EOVERFLOW) {
786 symtab_print_search(symbol);
787 printf("Duplicate symbol, be more specific.\n");
788 } else if (rc == EOK) {
789 ipl_t ipl;
790
791 ipl = interrupts_disable();
792 fnc = (sysarg_t (*)(sysarg_t, sysarg_t, ...))
793 arch_construct_function(&fptr, (void *) symaddr,
794 (void *) cmd_call2);
795 printf("Calling f(%#" PRIxn ", %#" PRIxn "): %p: %s\n",
796 arg1, arg2, (void *) symaddr, symbol);
797 printf("Result: %#" PRIxn "\n", fnc(arg1, arg2));
798 interrupts_restore(ipl);
799 } else {
800 printf("No symbol information available.\n");
801 }
802 return 1;
803}
804
805/** Call function with three parameters */
806int cmd_call3(cmd_arg_t *argv)
807{
808 uintptr_t symaddr;
809 char *symbol;
810 sysarg_t (*fnc)(sysarg_t, sysarg_t, sysarg_t, ...);
811 sysarg_t arg1 = argv[1].intval;
812 sysarg_t arg2 = argv[2].intval;
813 sysarg_t arg3 = argv[3].intval;
814 fncptr_t fptr;
815 int rc;
816
817 symbol = (char *) argv->buffer;
818 rc = symtab_addr_lookup(symbol, &symaddr);
819
820 if (rc == ENOENT) {
821 printf("Symbol %s not found.\n", symbol);
822 } else if (rc == EOVERFLOW) {
823 symtab_print_search(symbol);
824 printf("Duplicate symbol, be more specific.\n");
825 } else if (rc == EOK) {
826 ipl_t ipl;
827
828 ipl = interrupts_disable();
829 fnc = (sysarg_t (*)(sysarg_t, sysarg_t, sysarg_t, ...))
830 arch_construct_function(&fptr, (void *) symaddr,
831 (void *) cmd_call3);
832 printf("Calling f(%#" PRIxn ",%#" PRIxn ", %#" PRIxn "): %p: %s\n",
833 arg1, arg2, arg3, (void *) symaddr, symbol);
834 printf("Result: %#" PRIxn "\n", fnc(arg1, arg2, arg3));
835 interrupts_restore(ipl);
836 } else {
837 printf("No symbol information available.\n");
838 }
839 return 1;
840}
841
842/** Print detailed description of 'describe' command. */
843void desc_help(void)
844{
845 printf("Syntax: describe command_name\n");
846}
847
848/** Halt the kernel.
849 *
850 * @param argv Argument vector (ignored).
851 *
852 * @return 0 on failure, 1 on success (never returns).
853 */
854int cmd_halt(cmd_arg_t *argv)
855{
856 halt();
857 return 1;
858}
859
860/** Command for printing TLB contents.
861 *
862 * @param argv Not used.
863 *
864 * @return Always returns 1.
865 */
866int cmd_tlb(cmd_arg_t *argv)
867{
868 tlb_print();
869 return 1;
870}
871
872/** Command for printing physical memory configuration.
873 *
874 * @param argv Not used.
875 *
876 * @return Always returns 1.
877 */
878int cmd_physmem(cmd_arg_t *argv)
879{
880 physmem_print();
881 return 1;
882}
883
884/** Write 4 byte value to address */
885int cmd_set4(cmd_arg_t *argv)
886{
887 uintptr_t addr;
888 uint32_t arg1 = argv[1].intval;
889 bool pointer = false;
890 int rc;
891
892 if (((char *) argv->buffer)[0] == '*') {
893 rc = symtab_addr_lookup((char *) argv->buffer + 1, &addr);
894 pointer = true;
895 } else if (((char *) argv->buffer)[0] >= '0' &&
896 ((char *) argv->buffer)[0] <= '9') {
897 uint64_t value;
898 rc = str_uint64((char *) argv->buffer, NULL, 0, true, &value);
899 if (rc == EOK)
900 addr = (uintptr_t) value;
901 } else
902 rc = symtab_addr_lookup((char *) argv->buffer, &addr);
903
904 if (rc == ENOENT)
905 printf("Symbol %s not found.\n", (char *) argv->buffer);
906 else if (rc == EINVAL)
907 printf("Invalid address.\n");
908 else if (rc == EOVERFLOW) {
909 symtab_print_search((char *) argv->buffer);
910 printf("Duplicate symbol (be more specific) or address overflow.\n");
911 } else if (rc == EOK) {
912 if (pointer)
913 addr = *(uintptr_t *) addr;
914 printf("Writing %#" PRIx32" -> %p\n", arg1, (void *) addr);
915 *(uint32_t *) addr = arg1;
916 } else
917 printf("No symbol information available.\n");
918
919 return 1;
920}
921
922/** Command for listings SLAB caches
923 *
924 * @param argv Ignores
925 *
926 * @return Always 1
927 */
928int cmd_slabs(cmd_arg_t *argv)
929{
930 slab_print_list();
931 return 1;
932}
933
934/** Command for dumping sysinfo
935 *
936 * @param argv Ignores
937 *
938 * @return Always 1
939 */
940int cmd_sysinfo(cmd_arg_t *argv)
941{
942 sysinfo_dump(NULL);
943 return 1;
944}
945
946/** Command for listing thread information
947 *
948 * @param argv Ignored
949 *
950 * @return Always 1
951 */
952int cmd_threads(cmd_arg_t *argv)
953{
954 if (str_cmp(flag_buf, "-a") == 0)
955 thread_print_list(true);
956 else if (str_cmp(flag_buf, "") == 0)
957 thread_print_list(false);
958 else
959 printf("Unknown argument \"%s\".\n", flag_buf);
960
961 return 1;
962}
963
964/** Command for listing task information
965 *
966 * @param argv Ignored
967 *
968 * @return Always 1
969 */
970int cmd_tasks(cmd_arg_t *argv)
971{
972 if (str_cmp(flag_buf, "-a") == 0)
973 task_print_list(true);
974 else if (str_cmp(flag_buf, "") == 0)
975 task_print_list(false);
976 else
977 printf("Unknown argument \"%s\".\n", flag_buf);
978
979 return 1;
980}
981
982/** Command for printing thread stack trace
983 *
984 * @param argv Integer argument from cmdline expected
985 *
986 * return Always 1
987 *
988 */
989int cmd_btrace(cmd_arg_t *argv)
990{
991 thread_stack_trace(argv[0].intval);
992 return 1;
993}
994
995/** Command for printing scheduler information
996 *
997 * @param argv Ignores
998 *
999 * @return Always 1
1000 */
1001int cmd_sched(cmd_arg_t *argv)
1002{
1003 sched_print_list();
1004 return 1;
1005}
1006
1007/** Command for listing memory zones
1008 *
1009 * @param argv Ignored
1010 *
1011 * return Always 1
1012 */
1013int cmd_zones(cmd_arg_t *argv)
1014{
1015 zones_print_list();
1016 return 1;
1017}
1018
1019/** Command for memory zone details
1020 *
1021 * @param argv Integer argument from cmdline expected
1022 *
1023 * return Always 1
1024 */
1025int cmd_zone(cmd_arg_t *argv)
1026{
1027 zone_print_one(argv[0].intval);
1028 return 1;
1029}
1030
1031/** Command for printing task IPC details
1032 *
1033 * @param argv Integer argument from cmdline expected
1034 *
1035 * return Always 1
1036 */
1037int cmd_ipc(cmd_arg_t *argv)
1038{
1039 ipc_print_task(argv[0].intval);
1040 return 1;
1041}
1042
1043/** Command for killing a task
1044 *
1045 * @param argv Integer argument from cmdline expected
1046 *
1047 * return 0 on failure, 1 on success.
1048 */
1049int cmd_kill(cmd_arg_t *argv)
1050{
1051 if (task_kill(argv[0].intval) != EOK)
1052 return 0;
1053
1054 return 1;
1055}
1056
1057/** Command for listing processors.
1058 *
1059 * @param argv Ignored.
1060 *
1061 * return Always 1.
1062 */
1063int cmd_cpus(cmd_arg_t *argv)
1064{
1065 cpu_list();
1066 return 1;
1067}
1068
1069/** Command for printing kernel version.
1070 *
1071 * @param argv Ignored.
1072 *
1073 * return Always 1.
1074 */
1075int cmd_version(cmd_arg_t *argv)
1076{
1077 version_print();
1078 return 1;
1079}
1080
1081/** Command for returning console back to userspace.
1082 *
1083 * @param argv Ignored.
1084 *
1085 * return Always 1.
1086 */
1087int cmd_continue(cmd_arg_t *argv)
1088{
1089 printf("The kernel will now relinquish the console.\n");
1090 release_console();
1091
1092 event_notify_0(EVENT_KCONSOLE);
1093 indev_pop_character(stdin);
1094
1095 return 1;
1096}
1097
1098#ifdef CONFIG_TEST
1099static bool run_test(const test_t *test)
1100{
1101 printf("%s (%s)\n", test->name, test->desc);
1102
1103 /* Update and read thread accounting
1104 for benchmarking */
1105 irq_spinlock_lock(&TASK->lock, true);
1106 uint64_t ucycles0, kcycles0;
1107 task_get_accounting(TASK, &ucycles0, &kcycles0);
1108 irq_spinlock_unlock(&TASK->lock, true);
1109
1110 /* Execute the test */
1111 test_quiet = false;
1112 const char *ret = test->entry();
1113
1114 /* Update and read thread accounting */
1115 uint64_t ucycles1, kcycles1;
1116 irq_spinlock_lock(&TASK->lock, true);
1117 task_get_accounting(TASK, &ucycles1, &kcycles1);
1118 irq_spinlock_unlock(&TASK->lock, true);
1119
1120 uint64_t ucycles, kcycles;
1121 char usuffix, ksuffix;
1122 order_suffix(ucycles1 - ucycles0, &ucycles, &usuffix);
1123 order_suffix(kcycles1 - kcycles0, &kcycles, &ksuffix);
1124
1125 printf("Time: %" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles\n",
1126 ucycles, usuffix, kcycles, ksuffix);
1127
1128 if (ret == NULL) {
1129 printf("Test passed\n");
1130 return true;
1131 }
1132
1133 printf("%s\n", ret);
1134 return false;
1135}
1136
1137static bool run_bench(const test_t *test, const uint32_t cnt)
1138{
1139 uint32_t i;
1140 bool ret = true;
1141 uint64_t ucycles, kcycles;
1142 char usuffix, ksuffix;
1143
1144 if (cnt < 1)
1145 return true;
1146
1147 uint64_t *data = (uint64_t *) malloc(sizeof(uint64_t) * cnt, 0);
1148 if (data == NULL) {
1149 printf("Error allocating memory for statistics\n");
1150 return false;
1151 }
1152
1153 for (i = 0; i < cnt; i++) {
1154 printf("%s (%u/%u) ... ", test->name, i + 1, cnt);
1155
1156 /* Update and read thread accounting
1157 for benchmarking */
1158 irq_spinlock_lock(&TASK->lock, true);
1159 uint64_t ucycles0, kcycles0;
1160 task_get_accounting(TASK, &ucycles0, &kcycles0);
1161 irq_spinlock_unlock(&TASK->lock, true);
1162
1163 /* Execute the test */
1164 test_quiet = true;
1165 const char *ret = test->entry();
1166
1167 /* Update and read thread accounting */
1168 irq_spinlock_lock(&TASK->lock, true);
1169 uint64_t ucycles1, kcycles1;
1170 task_get_accounting(TASK, &ucycles1, &kcycles1);
1171 irq_spinlock_unlock(&TASK->lock, true);
1172
1173 if (ret != NULL) {
1174 printf("%s\n", ret);
1175 ret = false;
1176 break;
1177 }
1178
1179 data[i] = ucycles1 - ucycles0 + kcycles1 - kcycles0;
1180 order_suffix(ucycles1 - ucycles0, &ucycles, &usuffix);
1181 order_suffix(kcycles1 - kcycles0, &kcycles, &ksuffix);
1182 printf("OK (%" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles)\n",
1183 ucycles, usuffix, kcycles, ksuffix);
1184 }
1185
1186 if (ret) {
1187 printf("\n");
1188
1189 uint64_t sum = 0;
1190
1191 for (i = 0; i < cnt; i++) {
1192 sum += data[i];
1193 }
1194
1195 order_suffix(sum / (uint64_t) cnt, &ucycles, &usuffix);
1196 printf("Average\t\t%" PRIu64 "%c\n", ucycles, usuffix);
1197 }
1198
1199 free(data);
1200
1201 return ret;
1202}
1203
1204static void list_tests(void)
1205{
1206 size_t len = 0;
1207 test_t *test;
1208
1209 for (test = tests; test->name != NULL; test++) {
1210 if (str_length(test->name) > len)
1211 len = str_length(test->name);
1212 }
1213
1214 unsigned int _len = (unsigned int) len;
1215 if ((_len != len) || (((int) _len) < 0)) {
1216 printf("Command length overflow\n");
1217 return;
1218 }
1219
1220 for (test = tests; test->name != NULL; test++)
1221 printf("%-*s %s%s\n", _len, test->name, test->desc,
1222 (test->safe ? "" : " (unsafe)"));
1223
1224 printf("%-*s Run all safe tests\n", _len, "*");
1225}
1226
1227/** Command for listing and running kernel tests
1228 *
1229 * @param argv Argument vector.
1230 *
1231 * return Always 1.
1232 *
1233 */
1234int cmd_test(cmd_arg_t *argv)
1235{
1236 test_t *test;
1237
1238 if (str_cmp((char *) argv->buffer, "*") == 0) {
1239 for (test = tests; test->name != NULL; test++) {
1240 if (test->safe) {
1241 printf("\n");
1242 if (!run_test(test))
1243 break;
1244 }
1245 }
1246 } else if (str_cmp((char *) argv->buffer, "") != 0) {
1247 bool fnd = false;
1248
1249 for (test = tests; test->name != NULL; test++) {
1250 if (str_cmp(test->name, (char *) argv->buffer) == 0) {
1251 fnd = true;
1252 run_test(test);
1253 break;
1254 }
1255 }
1256
1257 if (!fnd)
1258 printf("Unknown test\n");
1259 } else
1260 list_tests();
1261
1262 return 1;
1263}
1264
1265/** Command for returning kernel tests as benchmarks
1266 *
1267 * @param argv Argument vector.
1268 *
1269 * return Always 1.
1270 */
1271int cmd_bench(cmd_arg_t *argv)
1272{
1273 test_t *test;
1274 uint32_t cnt = argv[1].intval;
1275
1276 if (str_cmp((char *) argv->buffer, "*") == 0) {
1277 for (test = tests; test->name != NULL; test++) {
1278 if (test->safe) {
1279 if (!run_bench(test, cnt))
1280 break;
1281 }
1282 }
1283 } else {
1284 bool fnd = false;
1285
1286 for (test = tests; test->name != NULL; test++) {
1287 if (str_cmp(test->name, (char *) argv->buffer) == 0) {
1288 fnd = true;
1289
1290 if (test->safe)
1291 run_bench(test, cnt);
1292 else
1293 printf("Unsafe test\n");
1294
1295 break;
1296 }
1297 }
1298
1299 if (!fnd)
1300 printf("Unknown test\n");
1301 }
1302
1303 return 1;
1304}
1305
1306#endif
1307
1308/** @}
1309 */
Note: See TracBrowser for help on using the repository browser.