source: mainline/kernel/generic/src/console/cmd.c@ 8b3bff5

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

merge "tests" and "test" kconsole commands

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