source: mainline/kernel/generic/src/console/cmd.c@ 2a34e4c

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

remove the confusing "exit" from the list of commands
(the exit command still works in last resort and debug consoles)

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