2
* Copyright (c) 2005 Jakub Jermar
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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.
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.
29
/** @addtogroup genericconsole
35
* @brief Kernel console command wrappers.
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.
43
#include <console/cmd.h>
44
#include <console/console.h>
45
#include <console/kconsole.h>
48
#include <arch/types.h>
58
#include <arch/mm/tlb.h>
60
#include <main/version.h>
62
#include <proc/scheduler.h>
63
#include <proc/thread.h>
64
#include <proc/task.h>
67
#include <ipc/event.h>
75
/* Data and methods for 'help' command. */
76
static int cmd_help(cmd_arg_t *argv);
77
static cmd_info_t help_info = {
79
.description = "List of supported commands.",
84
static int cmd_reboot(cmd_arg_t *argv);
85
static cmd_info_t reboot_info = {
87
.description = "Reboot.",
92
static int cmd_uptime(cmd_arg_t *argv);
93
static cmd_info_t uptime_info = {
95
.description = "Print uptime information.",
100
static int cmd_continue(cmd_arg_t *argv);
101
static cmd_info_t continue_info = {
103
.description = "Return console back to userspace.",
104
.func = cmd_continue,
109
static int cmd_tests(cmd_arg_t *argv);
110
static cmd_info_t tests_info = {
112
.description = "Print available kernel tests.",
117
static char test_buf[MAX_CMDLINE + 1];
118
static int cmd_test(cmd_arg_t *argv);
119
static cmd_arg_t test_argv[] = {
121
.type = ARG_TYPE_STRING,
123
.len = sizeof(test_buf)
126
static cmd_info_t test_info = {
128
.description = "Run kernel test.",
134
static int cmd_bench(cmd_arg_t *argv);
135
static cmd_arg_t bench_argv[] = {
137
.type = ARG_TYPE_STRING,
139
.len = sizeof(test_buf)
142
.type = ARG_TYPE_INT,
145
static cmd_info_t bench_info = {
147
.description = "Run kernel test as benchmark.",
154
/* Data and methods for 'description' command. */
155
static int cmd_desc(cmd_arg_t *argv);
156
static void desc_help(void);
157
static char desc_buf[MAX_CMDLINE+1];
158
static cmd_arg_t desc_argv = {
159
.type = ARG_TYPE_STRING,
161
.len = sizeof(desc_buf)
163
static cmd_info_t desc_info = {
165
.description = "Describe specified command.",
172
/* Data and methods for 'symaddr' command. */
173
static int cmd_symaddr(cmd_arg_t *argv);
174
static char symaddr_buf[MAX_CMDLINE+1];
175
static cmd_arg_t symaddr_argv = {
176
.type = ARG_TYPE_STRING,
177
.buffer = symaddr_buf,
178
.len = sizeof(symaddr_buf)
180
static cmd_info_t symaddr_info = {
182
.description = "Return symbol address.",
185
.argv = &symaddr_argv
188
static char set_buf[MAX_CMDLINE+1];
189
static int cmd_set4(cmd_arg_t *argv);
190
static cmd_arg_t set4_argv[] = {
192
.type = ARG_TYPE_STRING,
194
.len = sizeof(set_buf)
200
static cmd_info_t set4_info = {
202
.description = "set <dest_addr> <value> - 4byte version",
208
/* Data and methods for 'call0' command. */
209
static char call0_buf[MAX_CMDLINE + 1];
210
static char carg1_buf[MAX_CMDLINE + 1];
211
static char carg2_buf[MAX_CMDLINE + 1];
212
static char carg3_buf[MAX_CMDLINE + 1];
214
static int cmd_call0(cmd_arg_t *argv);
215
static cmd_arg_t call0_argv = {
216
.type = ARG_TYPE_STRING,
218
.len = sizeof(call0_buf)
220
static cmd_info_t call0_info = {
222
.description = "call0 <function> -> call function().",
228
/* Data and methods for 'mcall0' command. */
229
static int cmd_mcall0(cmd_arg_t *argv);
230
static cmd_arg_t mcall0_argv = {
231
.type = ARG_TYPE_STRING,
233
.len = sizeof(call0_buf)
235
static cmd_info_t mcall0_info = {
237
.description = "mcall0 <function> -> call function() on each CPU.",
243
/* Data and methods for 'call1' command. */
244
static int cmd_call1(cmd_arg_t *argv);
245
static cmd_arg_t call1_argv[] = {
247
.type = ARG_TYPE_STRING,
249
.len = sizeof(call0_buf)
252
.type = ARG_TYPE_VAR,
254
.len = sizeof(carg1_buf)
257
static cmd_info_t call1_info = {
259
.description = "call1 <function> <arg1> -> call function(arg1).",
265
/* Data and methods for 'call2' command. */
266
static int cmd_call2(cmd_arg_t *argv);
267
static cmd_arg_t call2_argv[] = {
269
.type = ARG_TYPE_STRING,
271
.len = sizeof(call0_buf)
274
.type = ARG_TYPE_VAR,
276
.len = sizeof(carg1_buf)
279
.type = ARG_TYPE_VAR,
281
.len = sizeof(carg2_buf)
284
static cmd_info_t call2_info = {
286
.description = "call2 <function> <arg1> <arg2> -> call function(arg1,arg2).",
292
/* Data and methods for 'call3' command. */
293
static int cmd_call3(cmd_arg_t *argv);
294
static cmd_arg_t call3_argv[] = {
296
.type = ARG_TYPE_STRING,
298
.len = sizeof(call0_buf)
301
.type = ARG_TYPE_VAR,
303
.len = sizeof(carg1_buf)
306
.type = ARG_TYPE_VAR,
308
.len = sizeof(carg2_buf)
311
.type = ARG_TYPE_VAR,
313
.len = sizeof(carg3_buf)
317
static cmd_info_t call3_info = {
319
.description = "call3 <function> <arg1> <arg2> <arg3> -> call function(arg1,arg2,arg3).",
325
/* Data and methods for 'halt' command. */
326
static int cmd_halt(cmd_arg_t *argv);
327
static cmd_info_t halt_info = {
329
.description = "Halt the kernel.",
334
/* Data and methods for 'physmem' command. */
335
static int cmd_physmem(cmd_arg_t *argv);
336
cmd_info_t physmem_info = {
338
.description = "Print physical memory configuration.",
345
/* Data and methods for 'tlb' command. */
346
static int cmd_tlb(cmd_arg_t *argv);
347
cmd_info_t tlb_info = {
349
.description = "Print TLB of current processor.",
356
static int cmd_threads(cmd_arg_t *argv);
357
static cmd_info_t threads_info = {
359
.description = "List all threads.",
364
static int cmd_tasks(cmd_arg_t *argv);
365
static cmd_info_t tasks_info = {
367
.description = "List all tasks.",
373
static int cmd_sched(cmd_arg_t *argv);
374
static cmd_info_t sched_info = {
376
.description = "List all scheduler information.",
381
static int cmd_slabs(cmd_arg_t *argv);
382
static cmd_info_t slabs_info = {
384
.description = "List slab caches.",
389
/* Data and methods for 'zones' command */
390
static int cmd_zones(cmd_arg_t *argv);
391
static cmd_info_t zones_info = {
393
.description = "List of memory zones.",
398
/* Data and methods for 'ipc' command */
399
static int cmd_ipc(cmd_arg_t *argv);
400
static cmd_arg_t ipc_argv = {
401
.type = ARG_TYPE_INT,
403
static cmd_info_t ipc_info = {
405
.description = "ipc <taskid> Show IPC information of given task.",
411
/* Data and methods for 'zone' command */
412
static int cmd_zone(cmd_arg_t *argv);
413
static cmd_arg_t zone_argv = {
414
.type = ARG_TYPE_INT,
417
static cmd_info_t zone_info = {
419
.description = "Show memory zone structure.",
425
/* Data and methods for 'cpus' command. */
426
static int cmd_cpus(cmd_arg_t *argv);
427
cmd_info_t cpus_info = {
429
.description = "List all processors.",
436
/* Data and methods for 'version' command. */
437
static int cmd_version(cmd_arg_t *argv);
438
cmd_info_t version_info = {
440
.description = "Print version information.",
447
static cmd_info_t *basic_commands[] = {
481
/** Initialize command info structure.
483
* @param cmd Command info structure.
486
void cmd_initialize(cmd_info_t *cmd)
488
spinlock_initialize(&cmd->lock, "cmd");
489
link_initialize(&cmd->link);
492
/** Initialize and register commands. */
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);
505
/** List supported commands.
507
* @param argv Argument vector.
509
* @return 0 on failure, 1 on success.
511
int cmd_help(cmd_arg_t *argv)
513
spinlock_lock(&cmd_lock);
517
for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
519
hlp = list_get_instance(cur, cmd_info_t, link);
521
spinlock_lock(&hlp->lock);
522
if (str_length(hlp->name) > len)
523
len = str_length(hlp->name);
524
spinlock_unlock(&hlp->lock);
527
for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
529
hlp = list_get_instance(cur, cmd_info_t, link);
531
spinlock_lock(&hlp->lock);
532
printf("%-*s %s\n", len, hlp->name, hlp->description);
533
spinlock_unlock(&hlp->lock);
536
spinlock_unlock(&cmd_lock);
542
/** Reboot the system.
544
* @param argv Argument vector.
546
* @return 0 on failure, 1 on success.
548
int cmd_reboot(cmd_arg_t *argv)
557
/** Print system uptime information.
559
* @param argv Argument vector.
561
* @return 0 on failure, 1 on success.
563
int cmd_uptime(cmd_arg_t *argv)
567
/* This doesn't have to be very accurate */
568
unative_t sec = uptime->seconds1;
570
printf("Up %" PRIun " days, %" PRIun " hours, %" PRIun " minutes, %" PRIun " seconds\n",
571
sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
576
/** Describe specified command.
578
* @param argv Argument vector.
580
* @return 0 on failure, 1 on success.
582
int cmd_desc(cmd_arg_t *argv)
586
spinlock_lock(&cmd_lock);
588
for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
591
hlp = list_get_instance(cur, cmd_info_t, link);
592
spinlock_lock(&hlp->lock);
594
if (str_lcmp(hlp->name, (const char *) argv->buffer, str_length(hlp->name)) == 0) {
595
printf("%s - %s\n", hlp->name, hlp->description);
598
spinlock_unlock(&hlp->lock);
602
spinlock_unlock(&hlp->lock);
605
spinlock_unlock(&cmd_lock);
610
/** Search symbol table */
611
int cmd_symaddr(cmd_arg_t *argv)
613
symtab_print_search((char *) argv->buffer);
618
/** Call function with zero parameters */
619
int cmd_call0(cmd_arg_t *argv)
623
unative_t (*fnc)(void);
627
symbol = (char *) argv->buffer;
628
rc = symtab_addr_lookup(symbol, &symaddr);
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());
641
printf("No symbol information available.\n");
646
/** Call function with zero parameters on each CPU */
647
int cmd_mcall0(cmd_arg_t *argv)
650
* For each CPU, create a thread which will
655
for (i = 0; i < config.cpu_count; i++) {
660
if ((t = thread_create((void (*)(void *)) cmd_call0, (void *) argv, TASK, THREAD_FLAG_WIRED, "call0", false))) {
661
spinlock_lock(&t->lock);
663
spinlock_unlock(&t->lock);
664
printf("cpu%u: ", i);
669
printf("Unable to create thread for cpu%u\n", i);
675
/** Call function with one parameter */
676
int cmd_call1(cmd_arg_t *argv)
680
unative_t (*fnc)(unative_t, ...);
681
unative_t arg1 = argv[1].intval;
685
symbol = (char *) argv->buffer;
686
rc = symtab_addr_lookup(symbol, &symaddr);
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));
698
printf("No symbol information available.\n");
704
/** Call function with two parameters */
705
int cmd_call2(cmd_arg_t *argv)
709
unative_t (*fnc)(unative_t, unative_t, ...);
710
unative_t arg1 = argv[1].intval;
711
unative_t arg2 = argv[2].intval;
715
symbol = (char *) argv->buffer;
716
rc = symtab_addr_lookup(symbol, &symaddr);
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));
729
printf("No symbol information available.\n");
734
/** Call function with three parameters */
735
int cmd_call3(cmd_arg_t *argv)
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;
746
symbol = (char *) argv->buffer;
747
rc = symtab_addr_lookup(symbol, &symaddr);
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));
760
printf("No symbol information available.\n");
766
/** Print detailed description of 'describe' command. */
769
printf("Syntax: describe command_name\n");
774
* @param argv Argument vector (ignored).
776
* @return 0 on failure, 1 on success (never returns).
778
int cmd_halt(cmd_arg_t *argv)
784
/** Command for printing TLB contents.
786
* @param argv Not used.
788
* @return Always returns 1.
790
int cmd_tlb(cmd_arg_t *argv)
796
/** Command for printing physical memory configuration.
798
* @param argv Not used.
800
* @return Always returns 1.
802
int cmd_physmem(cmd_arg_t *argv)
808
/** Write 4 byte value to address */
809
int cmd_set4(cmd_arg_t *argv)
812
uint32_t arg1 = argv[1].intval;
813
bool pointer = false;
816
if (((char *)argv->buffer)[0] == '*') {
817
rc = symtab_addr_lookup((char *) argv->buffer + 1, &addr);
819
} else if (((char *) argv->buffer)[0] >= '0' &&
820
((char *)argv->buffer)[0] <= '9') {
822
addr = atoi((char *)argv->buffer);
824
rc = symtab_addr_lookup((char *) argv->buffer, &addr);
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) {
834
addr = *(uintptr_t *) addr;
835
printf("Writing %#" PRIx64 " -> %p\n", arg1, addr);
836
*(uint32_t *) addr = arg1;
838
printf("No symbol information available.\n");
844
/** Command for listings SLAB caches
846
* @param argv Ignores
850
int cmd_slabs(cmd_arg_t * argv) {
856
/** Command for listings Thread information
858
* @param argv Ignores
862
int cmd_threads(cmd_arg_t * argv) {
867
/** Command for listings Task information
869
* @param argv Ignores
873
int cmd_tasks(cmd_arg_t * argv) {
878
/** Command for listings Thread information
880
* @param argv Ignores
884
int cmd_sched(cmd_arg_t * argv) {
889
/** Command for listing memory zones
891
* @param argv Ignored
895
int cmd_zones(cmd_arg_t * argv) {
900
/** Command for memory zone details
902
* @param argv Integer argument from cmdline expected
906
int cmd_zone(cmd_arg_t * argv) {
907
zone_print_one(argv[0].intval);
911
/** Command for printing task ipc details
913
* @param argv Integer argument from cmdline expected
917
int cmd_ipc(cmd_arg_t * argv) {
918
ipc_print_task(argv[0].intval);
923
/** Command for listing processors.
925
* @param argv Ignored.
929
int cmd_cpus(cmd_arg_t *argv)
935
/** Command for printing kernel version.
937
* @param argv Ignored.
941
int cmd_version(cmd_arg_t *argv)
947
/** Command for returning console back to userspace.
949
* @param argv Ignored.
953
int cmd_continue(cmd_arg_t *argv)
955
printf("The kernel will now relinquish the console.\n");
958
event_notify_0(EVENT_KCONSOLE);
959
indev_pop_character(stdin);
965
/** Command for printing kernel tests list.
967
* @param argv Ignored.
971
int cmd_tests(cmd_arg_t *argv)
975
for (test = tests; test->name != NULL; test++) {
976
if (str_length(test->name) > len)
977
len = str_length(test->name);
980
for (test = tests; test->name != NULL; test++)
981
printf("%-*s %s%s\n", len, test->name, test->desc, (test->safe ? "" : " (unsafe)"));
983
printf("%-*s Run all safe tests\n", len, "*");
987
static bool run_test(const test_t *test)
989
printf("%s (%s)\n", test->name, test->desc);
991
/* Update and read thread accounting
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);
999
/* Execute the test */
1001
char *ret = test->entry();
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);
1012
order(dt, &cycles, &suffix);
1014
printf("Time: %" PRIu64 "%c cycles\n", cycles, suffix);
1017
printf("Test passed\n");
1021
printf("%s\n", ret);
1025
static bool run_bench(const test_t *test, const uint32_t cnt)
1035
uint64_t *data = (uint64_t *) malloc(sizeof(uint64_t) * cnt, 0);
1037
printf("Error allocating memory for statistics\n");
1041
for (i = 0; i < cnt; i++) {
1042
printf("%s (%u/%u) ... ", test->name, i + 1, cnt);
1044
/* Update and read thread accounting
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);
1052
/* Execute the test */
1054
char * ret = test->entry();
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);
1064
printf("%s\n", ret);
1070
order(dt, &cycles, &suffix);
1071
printf("OK (%" PRIu64 "%c cycles)\n", cycles, suffix);
1079
for (i = 0; i < cnt; i++) {
1083
order(sum / (uint64_t) cnt, &cycles, &suffix);
1084
printf("Average\t\t%" PRIu64 "%c\n", cycles, suffix);
1092
/** Command for returning kernel tests
1094
* @param argv Argument vector.
1098
int cmd_test(cmd_arg_t *argv)
1102
if (str_cmp((char *) argv->buffer, "*") == 0) {
1103
for (test = tests; test->name != NULL; test++) {
1106
if (!run_test(test))
1113
for (test = tests; test->name != NULL; test++) {
1114
if (str_cmp(test->name, (char *) argv->buffer) == 0) {
1122
printf("Unknown test\n");
1128
/** Command for returning kernel tests as benchmarks
1130
* @param argv Argument vector.
1134
int cmd_bench(cmd_arg_t *argv)
1137
uint32_t cnt = argv[1].intval;
1139
if (str_cmp((char *) argv->buffer, "*") == 0) {
1140
for (test = tests; test->name != NULL; test++) {
1142
if (!run_bench(test, cnt))
1149
for (test = tests; test->name != NULL; test++) {
1150
if (str_cmp(test->name, (char *) argv->buffer) == 0) {
1154
run_bench(test, cnt);
1156
printf("Unsafe test\n");
1163
printf("Unknown test\n");