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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 97d42d5 was f9061b4, checked in by Martin Decky <martin@…>, 14 years ago

add kernel event notification masking (currently used only for EVENT_KLOG)
improve kernel event notification API

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