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

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

better printouts for threads

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