source: mainline/kernel/generic/src/console/cmd.c@ 821cc93

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

make the 'continue' command behave even nicer

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