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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5d230a30 was 181a746, checked in by Adam Hraska <adam.hraska+hos@…>, 13 years ago

rcu: Added preemptible RCU's core API implementation.

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