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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8b3bff5 was 851f33a, checked in by Martin Decky <martin@…>, 15 years ago

merge "tests" and "test" kconsole commands

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