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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 20f1597 was 16da5f8e, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

String functions should be declared in string.h (and implemented in string.c) in the kernel.

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