source: mainline/kernel/generic/src/console/cmd.c@ 7329e6a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7329e6a was 0b0f4bb, checked in by Martin Decky <martin@…>, 15 years ago
  • correct printf() formatting strings and corresponding arguments
  • add explicit overflow checking to printf-related code
  • Property mode set to 100644
File size: 27.0 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
[0b0f4bb]556 unsigned int _len = (unsigned int) len;
557 if ((_len != len) || (((int) _len) < 0)) {
558 printf("Command length overflow\n");
559 return 1;
560 }
561
[c1f7f6ea]562 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
563 cmd_info_t *hlp;
564 hlp = list_get_instance(cur, cmd_info_t, link);
[442d0ae]565
[c1f7f6ea]566 spinlock_lock(&hlp->lock);
[0b0f4bb]567 printf("%-*s %s\n", _len, hlp->name, hlp->description);
[442d0ae]568 spinlock_unlock(&hlp->lock);
569 }
570
[ae318d3]571 spinlock_unlock(&cmd_lock);
[c1f7f6ea]572
[442d0ae]573 return 1;
574}
575
[f74bbaf]576
577/** Reboot the system.
578 *
579 * @param argv Argument vector.
580 *
581 * @return 0 on failure, 1 on success.
582 */
583int cmd_reboot(cmd_arg_t *argv)
584{
585 reboot();
586
587 /* Not reached */
588 return 1;
589}
590
[4b662f8c]591
592/** Print system uptime information.
593 *
594 * @param argv Argument vector.
595 *
596 * @return 0 on failure, 1 on success.
597 */
598int cmd_uptime(cmd_arg_t *argv)
599{
600 ASSERT(uptime);
601
602 /* This doesn't have to be very accurate */
603 unative_t sec = uptime->seconds1;
604
[c859753]605 printf("Up %" PRIun " days, %" PRIun " hours, %" PRIun " minutes, %" PRIun " seconds\n",
[4b662f8c]606 sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
607
608 return 1;
609}
610
[442d0ae]611/** Describe specified command.
612 *
613 * @param argv Argument vector.
614 *
615 * @return 0 on failure, 1 on success.
616 */
617int cmd_desc(cmd_arg_t *argv)
618{
619 link_t *cur;
[20cc877]620
[442d0ae]621 spinlock_lock(&cmd_lock);
622
623 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
624 cmd_info_t *hlp;
625
626 hlp = list_get_instance(cur, cmd_info_t, link);
627 spinlock_lock(&hlp->lock);
[20cc877]628
629 if (str_lcmp(hlp->name, (const char *) argv->buffer, str_length(hlp->name)) == 0) {
[442d0ae]630 printf("%s - %s\n", hlp->name, hlp->description);
631 if (hlp->help)
632 hlp->help();
633 spinlock_unlock(&hlp->lock);
634 break;
635 }
[20cc877]636
[442d0ae]637 spinlock_unlock(&hlp->lock);
638 }
639
640 spinlock_unlock(&cmd_lock);
[20cc877]641
[442d0ae]642 return 1;
643}
644
645/** Search symbol table */
646int cmd_symaddr(cmd_arg_t *argv)
647{
[828aa05]648 symtab_print_search((char *) argv->buffer);
[442d0ae]649
650 return 1;
651}
652
653/** Call function with zero parameters */
654int cmd_call0(cmd_arg_t *argv)
655{
[7f1c620]656 uintptr_t symaddr;
[e16e0d59]657 char *symbol;
[0f81ceb7]658 unative_t (*fnc)(void);
659 fncptr_t fptr;
[e16e0d59]660 int rc;
[e2b762ec]661
[e16e0d59]662 symbol = (char *) argv->buffer;
663 rc = symtab_addr_lookup(symbol, &symaddr);
664
665 if (rc == ENOENT)
666 printf("Symbol %s not found.\n", symbol);
667 else if (rc == EOVERFLOW) {
668 symtab_print_search(symbol);
[442d0ae]669 printf("Duplicate symbol, be more specific.\n");
[e16e0d59]670 } else if (rc == EOK) {
[c992538a]671 ipl_t ipl;
672
673 ipl = interrupts_disable();
[e16e0d59]674 fnc = (unative_t (*)(void)) arch_construct_function(&fptr,
675 (void *) symaddr, (void *) cmd_call0);
[0b0f4bb]676 printf("Calling %s() (%p)\n", symbol, (void *) symaddr);
[0f81ceb7]677 printf("Result: %#" PRIxn "\n", fnc());
[c992538a]678 interrupts_restore(ipl);
[e16e0d59]679 } else {
680 printf("No symbol information available.\n");
[442d0ae]681 }
682 return 1;
683}
684
[e5dbbe5]685/** Call function with zero parameters on each CPU */
686int cmd_mcall0(cmd_arg_t *argv)
687{
688 /*
689 * For each CPU, create a thread which will
690 * call the function.
691 */
692
[0b0f4bb]693 unsigned int i;
[e5dbbe5]694 for (i = 0; i < config.cpu_count; i++) {
[b8f11baa]695 if (!cpus[i].active)
696 continue;
697
[da1bafb]698 thread_t *thread;
699 if ((thread = thread_create((void (*)(void *)) cmd_call0,
700 (void *) argv, TASK, THREAD_FLAG_WIRED, "call0", false))) {
701 irq_spinlock_lock(&thread->lock, true);
702 thread->cpu = &cpus[i];
703 irq_spinlock_unlock(&thread->lock, true);
704
[0b0f4bb]705 printf("cpu%u: ", i);
[da1bafb]706
707 thread_ready(thread);
708 thread_join(thread);
709 thread_detach(thread);
[e5dbbe5]710 } else
[0b0f4bb]711 printf("Unable to create thread for cpu%u\n", i);
[e5dbbe5]712 }
713
714 return 1;
715}
716
[442d0ae]717/** Call function with one parameter */
718int cmd_call1(cmd_arg_t *argv)
719{
[7f1c620]720 uintptr_t symaddr;
[442d0ae]721 char *symbol;
[0f81ceb7]722 unative_t (*fnc)(unative_t, ...);
[7f1c620]723 unative_t arg1 = argv[1].intval;
[0f81ceb7]724 fncptr_t fptr;
[e16e0d59]725 int rc;
[e2b762ec]726
[e16e0d59]727 symbol = (char *) argv->buffer;
728 rc = symtab_addr_lookup(symbol, &symaddr);
729
730 if (rc == ENOENT) {
731 printf("Symbol %s not found.\n", symbol);
732 } else if (rc == EOVERFLOW) {
733 symtab_print_search(symbol);
[442d0ae]734 printf("Duplicate symbol, be more specific.\n");
[e16e0d59]735 } else if (rc == EOK) {
[c992538a]736 ipl_t ipl;
737
738 ipl = interrupts_disable();
[0b0f4bb]739 fnc = (unative_t (*)(unative_t, ...))
740 arch_construct_function(&fptr, (void *) symaddr,
741 (void *) cmd_call1);
742 printf("Calling f(%#" PRIxn "): %p: %s\n", arg1,
743 (void *) symaddr, symbol);
[0f81ceb7]744 printf("Result: %#" PRIxn "\n", fnc(arg1));
[c992538a]745 interrupts_restore(ipl);
[e16e0d59]746 } else {
747 printf("No symbol information available.\n");
[442d0ae]748 }
[e16e0d59]749
[442d0ae]750 return 1;
751}
752
753/** Call function with two parameters */
754int cmd_call2(cmd_arg_t *argv)
755{
[7f1c620]756 uintptr_t symaddr;
[442d0ae]757 char *symbol;
[0f81ceb7]758 unative_t (*fnc)(unative_t, unative_t, ...);
[7f1c620]759 unative_t arg1 = argv[1].intval;
760 unative_t arg2 = argv[2].intval;
[0f81ceb7]761 fncptr_t fptr;
[e16e0d59]762 int rc;
763
764 symbol = (char *) argv->buffer;
765 rc = symtab_addr_lookup(symbol, &symaddr);
766
767 if (rc == ENOENT) {
768 printf("Symbol %s not found.\n", symbol);
769 } else if (rc == EOVERFLOW) {
770 symtab_print_search(symbol);
[442d0ae]771 printf("Duplicate symbol, be more specific.\n");
[e16e0d59]772 } else if (rc == EOK) {
[c992538a]773 ipl_t ipl;
774
775 ipl = interrupts_disable();
[0b0f4bb]776 fnc = (unative_t (*)(unative_t, unative_t, ...))
777 arch_construct_function(&fptr, (void *) symaddr,
778 (void *) cmd_call2);
[c859753]779 printf("Calling f(%#" PRIxn ", %#" PRIxn "): %p: %s\n",
[0b0f4bb]780 arg1, arg2, (void *) symaddr, symbol);
[0f81ceb7]781 printf("Result: %#" PRIxn "\n", fnc(arg1, arg2));
[c992538a]782 interrupts_restore(ipl);
[e16e0d59]783 } else {
784 printf("No symbol information available.\n");
785 }
[442d0ae]786 return 1;
787}
788
789/** Call function with three parameters */
790int cmd_call3(cmd_arg_t *argv)
791{
[7f1c620]792 uintptr_t symaddr;
[442d0ae]793 char *symbol;
[0f81ceb7]794 unative_t (*fnc)(unative_t, unative_t, unative_t, ...);
[7f1c620]795 unative_t arg1 = argv[1].intval;
796 unative_t arg2 = argv[2].intval;
797 unative_t arg3 = argv[3].intval;
[0f81ceb7]798 fncptr_t fptr;
[e16e0d59]799 int rc;
[0f81ceb7]800
[e16e0d59]801 symbol = (char *) argv->buffer;
802 rc = symtab_addr_lookup(symbol, &symaddr);
803
804 if (rc == ENOENT) {
805 printf("Symbol %s not found.\n", symbol);
806 } else if (rc == EOVERFLOW) {
807 symtab_print_search(symbol);
[442d0ae]808 printf("Duplicate symbol, be more specific.\n");
[e16e0d59]809 } else if (rc == EOK) {
[c992538a]810 ipl_t ipl;
811
812 ipl = interrupts_disable();
[0b0f4bb]813 fnc = (unative_t (*)(unative_t, unative_t, unative_t, ...))
814 arch_construct_function(&fptr, (void *) symaddr,
815 (void *) cmd_call3);
816 printf("Calling f(%#" PRIxn ",%#" PRIxn ", %#" PRIxn "): %p: %s\n",
817 arg1, arg2, arg3, (void *) symaddr, symbol);
[0f81ceb7]818 printf("Result: %#" PRIxn "\n", fnc(arg1, arg2, arg3));
[c992538a]819 interrupts_restore(ipl);
[e16e0d59]820 } else {
821 printf("No symbol information available.\n");
[442d0ae]822 }
823 return 1;
824}
825
826
827/** Print detailed description of 'describe' command. */
828void desc_help(void)
829{
830 printf("Syntax: describe command_name\n");
831}
832
833/** Halt the kernel.
834 *
835 * @param argv Argument vector (ignored).
836 *
837 * @return 0 on failure, 1 on success (never returns).
838 */
839int cmd_halt(cmd_arg_t *argv)
840{
841 halt();
842 return 1;
843}
844
845/** Command for printing TLB contents.
846 *
847 * @param argv Not used.
848 *
849 * @return Always returns 1.
850 */
[0132630]851int cmd_tlb(cmd_arg_t *argv)
[442d0ae]852{
853 tlb_print();
854 return 1;
855}
[ba276f7]856
[b07c332]857/** Command for printing physical memory configuration.
858 *
859 * @param argv Not used.
860 *
861 * @return Always returns 1.
862 */
863int cmd_physmem(cmd_arg_t *argv)
864{
865 physmem_print();
866 return 1;
867}
868
[ba276f7]869/** Write 4 byte value to address */
870int cmd_set4(cmd_arg_t *argv)
871{
[e16e0d59]872 uintptr_t addr;
[7f1c620]873 uint32_t arg1 = argv[1].intval;
[ba276f7]874 bool pointer = false;
[e16e0d59]875 int rc;
[4ce914d4]876
877 if (((char *) argv->buffer)[0] == '*') {
[e16e0d59]878 rc = symtab_addr_lookup((char *) argv->buffer + 1, &addr);
[ba276f7]879 pointer = true;
[4ce914d4]880 } else if (((char *) argv->buffer)[0] >= '0' &&
881 ((char *) argv->buffer)[0] <= '9') {
882 uint64_t value;
883 rc = str_uint64((char *) argv->buffer, NULL, 0, true, &value);
884 if (rc == EOK)
885 addr = (uintptr_t) value;
886 } else
[e16e0d59]887 rc = symtab_addr_lookup((char *) argv->buffer, &addr);
[4ce914d4]888
[e16e0d59]889 if (rc == ENOENT)
[0b0f4bb]890 printf("Symbol %s not found.\n", (char *) argv->buffer);
[4ce914d4]891 else if (rc == EINVAL)
892 printf("Invalid address.\n");
[e16e0d59]893 else if (rc == EOVERFLOW) {
[828aa05]894 symtab_print_search((char *) argv->buffer);
[4ce914d4]895 printf("Duplicate symbol (be more specific) or address overflow.\n");
[e16e0d59]896 } else if (rc == EOK) {
[ba276f7]897 if (pointer)
[e16e0d59]898 addr = *(uintptr_t *) addr;
[0b0f4bb]899 printf("Writing %#" PRIx32" -> %p\n", arg1, (void *) addr);
[e16e0d59]900 *(uint32_t *) addr = arg1;
[4ce914d4]901 } else
[e16e0d59]902 printf("No symbol information available.\n");
[ba276f7]903
904 return 1;
905}
[80bff342]906
[4e147a6]907/** Command for listings SLAB caches
908 *
909 * @param argv Ignores
910 *
911 * @return Always 1
912 */
[095b1534]913int cmd_slabs(cmd_arg_t * argv)
914{
[4e147a6]915 slab_print_list();
916 return 1;
917}
918
[b3631bc]919/** Command for dumping sysinfo
920 *
921 * @param argv Ignores
922 *
923 * @return Always 1
924 */
925int cmd_sysinfo(cmd_arg_t * argv)
926{
[9dae191e]927 sysinfo_dump(NULL);
[b3631bc]928 return 1;
929}
930
[55ab0f1]931
932/** Command for listings Thread information
933 *
[48dcc69]934 * @param argv Ignored
[55ab0f1]935 *
936 * @return Always 1
937 */
[48dcc69]938int cmd_threads(cmd_arg_t *argv)
[095b1534]939{
[48dcc69]940 if (str_cmp(flag_buf, "-a") == 0)
941 thread_print_list(true);
942 else if (str_cmp(flag_buf, "") == 0)
943 thread_print_list(false);
944 else
945 printf("Unknown argument \"%s\".\n", flag_buf);
946
[55ab0f1]947 return 1;
948}
949
[37c57f2]950/** Command for listings Task information
951 *
[48dcc69]952 * @param argv Ignored
[37c57f2]953 *
954 * @return Always 1
955 */
[c0f13d2]956int cmd_tasks(cmd_arg_t *argv)
[095b1534]957{
[48dcc69]958 if (str_cmp(flag_buf, "-a") == 0)
[c0f13d2]959 task_print_list(true);
[48dcc69]960 else if (str_cmp(flag_buf, "") == 0)
[c0f13d2]961 task_print_list(false);
962 else
[48dcc69]963 printf("Unknown argument \"%s\".\n", flag_buf);
[c0f13d2]964
[37c57f2]965 return 1;
966}
967
[10e16a7]968/** Command for listings Thread information
969 *
970 * @param argv Ignores
971 *
972 * @return Always 1
973 */
[095b1534]974int cmd_sched(cmd_arg_t * argv)
975{
[10e16a7]976 sched_print_list();
977 return 1;
978}
979
[96cacc1]980/** Command for listing memory zones
981 *
982 * @param argv Ignored
983 *
984 * return Always 1
985 */
[095b1534]986int cmd_zones(cmd_arg_t * argv)
987{
[9dae191e]988 zones_print_list();
[80bff342]989 return 1;
990}
[0132630]991
[96cacc1]992/** Command for memory zone details
993 *
994 * @param argv Integer argument from cmdline expected
995 *
996 * return Always 1
997 */
[095b1534]998int cmd_zone(cmd_arg_t * argv)
999{
[dfd9186]1000 zone_print_one(argv[0].intval);
[80bff342]1001 return 1;
1002}
1003
[c4e4507]1004/** Command for printing task ipc details
1005 *
1006 * @param argv Integer argument from cmdline expected
1007 *
1008 * return Always 1
1009 */
[095b1534]1010int cmd_ipc(cmd_arg_t * argv)
1011{
[c4e4507]1012 ipc_print_task(argv[0].intval);
1013 return 1;
1014}
1015
[cb3d641a]1016/** Command for killing a task
[2a75302]1017 *
1018 * @param argv Integer argument from cmdline expected
1019 *
[cb3d641a]1020 * return 0 on failure, 1 on success.
[2a75302]1021 */
1022int cmd_kill(cmd_arg_t * argv)
1023{
1024 if (task_kill(argv[0].intval) != EOK)
1025 return 0;
1026
1027 return 1;
1028}
[c4e4507]1029
[0132630]1030/** Command for listing processors.
1031 *
1032 * @param argv Ignored.
1033 *
1034 * return Always 1.
1035 */
1036int cmd_cpus(cmd_arg_t *argv)
1037{
1038 cpu_list();
1039 return 1;
1040}
1041
1042/** Command for printing kernel version.
1043 *
1044 * @param argv Ignored.
1045 *
1046 * return Always 1.
1047 */
1048int cmd_version(cmd_arg_t *argv)
1049{
1050 version_print();
1051 return 1;
1052}
[41d33ac]1053
1054/** Command for returning console back to userspace.
1055 *
1056 * @param argv Ignored.
1057 *
1058 * return Always 1.
1059 */
1060int cmd_continue(cmd_arg_t *argv)
1061{
[dd054bc2]1062 printf("The kernel will now relinquish the console.\n");
[516ff92]1063 release_console();
[3ad953c]1064
[05641a9e]1065 event_notify_0(EVENT_KCONSOLE);
[821cc93]1066 indev_pop_character(stdin);
[3ad953c]1067
[41d33ac]1068 return 1;
1069}
[b45c443]1070
[50661ab]1071#ifdef CONFIG_TEST
[62b6d17]1072static bool run_test(const test_t *test)
[34db7fa]1073{
[c1f7f6ea]1074 printf("%s (%s)\n", test->name, test->desc);
[cce6acf]1075
1076 /* Update and read thread accounting
1077 for benchmarking */
[da1bafb]1078 irq_spinlock_lock(&TASK->lock, true);
[1ba37fa]1079 uint64_t ucycles0, kcycles0;
1080 task_get_accounting(TASK, &ucycles0, &kcycles0);
[da1bafb]1081 irq_spinlock_unlock(&TASK->lock, true);
[cce6acf]1082
1083 /* Execute the test */
[cb01e1e]1084 test_quiet = false;
[a000878c]1085 const char *ret = test->entry();
[cce6acf]1086
1087 /* Update and read thread accounting */
[da1bafb]1088 uint64_t ucycles1, kcycles1;
1089 irq_spinlock_lock(&TASK->lock, true);
[1ba37fa]1090 task_get_accounting(TASK, &ucycles1, &kcycles1);
[da1bafb]1091 irq_spinlock_unlock(&TASK->lock, true);
[cce6acf]1092
[1ba37fa]1093 uint64_t ucycles, kcycles;
1094 char usuffix, ksuffix;
[e535eeb]1095 order_suffix(ucycles1 - ucycles0, &ucycles, &usuffix);
1096 order_suffix(kcycles1 - kcycles0, &kcycles, &ksuffix);
[da1bafb]1097
[1ba37fa]1098 printf("Time: %" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles\n",
[da1bafb]1099 ucycles, usuffix, kcycles, ksuffix);
[34db7fa]1100
1101 if (ret == NULL) {
1102 printf("Test passed\n");
[62b6d17]1103 return true;
[34db7fa]1104 }
[da1bafb]1105
[34db7fa]1106 printf("%s\n", ret);
[62b6d17]1107 return false;
[34db7fa]1108}
1109
[95155b0c]1110static bool run_bench(const test_t *test, const uint32_t cnt)
1111{
1112 uint32_t i;
1113 bool ret = true;
[1ba37fa]1114 uint64_t ucycles, kcycles;
1115 char usuffix, ksuffix;
[95155b0c]1116
1117 if (cnt < 1)
1118 return true;
1119
[828aa05]1120 uint64_t *data = (uint64_t *) malloc(sizeof(uint64_t) * cnt, 0);
[95155b0c]1121 if (data == NULL) {
1122 printf("Error allocating memory for statistics\n");
1123 return false;
1124 }
1125
1126 for (i = 0; i < cnt; i++) {
[c859753]1127 printf("%s (%u/%u) ... ", test->name, i + 1, cnt);
[95155b0c]1128
1129 /* Update and read thread accounting
1130 for benchmarking */
[da1bafb]1131 irq_spinlock_lock(&TASK->lock, true);
[1ba37fa]1132 uint64_t ucycles0, kcycles0;
1133 task_get_accounting(TASK, &ucycles0, &kcycles0);
[da1bafb]1134 irq_spinlock_unlock(&TASK->lock, true);
[95155b0c]1135
1136 /* Execute the test */
[cb01e1e]1137 test_quiet = true;
[a000878c]1138 const char *ret = test->entry();
[95155b0c]1139
1140 /* Update and read thread accounting */
[da1bafb]1141 irq_spinlock_lock(&TASK->lock, true);
[1ba37fa]1142 uint64_t ucycles1, kcycles1;
1143 task_get_accounting(TASK, &ucycles1, &kcycles1);
[da1bafb]1144 irq_spinlock_unlock(&TASK->lock, true);
1145
[95155b0c]1146 if (ret != NULL) {
1147 printf("%s\n", ret);
1148 ret = false;
1149 break;
1150 }
1151
[1ba37fa]1152 data[i] = ucycles1 - ucycles0 + kcycles1 - kcycles0;
[e535eeb]1153 order_suffix(ucycles1 - ucycles0, &ucycles, &usuffix);
1154 order_suffix(kcycles1 - kcycles0, &kcycles, &ksuffix);
[1ba37fa]1155 printf("OK (%" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles)\n",
[da1bafb]1156 ucycles, usuffix, kcycles, ksuffix);
[95155b0c]1157 }
1158
1159 if (ret) {
1160 printf("\n");
1161
1162 uint64_t sum = 0;
1163
1164 for (i = 0; i < cnt; i++) {
1165 sum += data[i];
1166 }
1167
[e535eeb]1168 order_suffix(sum / (uint64_t) cnt, &ucycles, &usuffix);
[1ba37fa]1169 printf("Average\t\t%" PRIu64 "%c\n", ucycles, usuffix);
[95155b0c]1170 }
1171
1172 free(data);
1173
1174 return ret;
1175}
1176
[851f33a]1177static void list_tests(void)
1178{
1179 size_t len = 0;
1180 test_t *test;
1181
1182 for (test = tests; test->name != NULL; test++) {
1183 if (str_length(test->name) > len)
1184 len = str_length(test->name);
1185 }
1186
[0b0f4bb]1187 unsigned int _len = (unsigned int) len;
1188 if ((_len != len) || (((int) _len) < 0)) {
1189 printf("Command length overflow\n");
1190 return;
1191 }
1192
[851f33a]1193 for (test = tests; test->name != NULL; test++)
[0b0f4bb]1194 printf("%-*s %s%s\n", _len, test->name, test->desc,
1195 (test->safe ? "" : " (unsafe)"));
[851f33a]1196
[0b0f4bb]1197 printf("%-*s Run all safe tests\n", _len, "*");
[851f33a]1198}
1199
1200/** Command for listing and running kernel tests
[319e60e]1201 *
1202 * @param argv Argument vector.
1203 *
1204 * return Always 1.
[851f33a]1205 *
[319e60e]1206 */
1207int cmd_test(cmd_arg_t *argv)
1208{
1209 test_t *test;
1210
[20cc877]1211 if (str_cmp((char *) argv->buffer, "*") == 0) {
[50661ab]1212 for (test = tests; test->name != NULL; test++) {
1213 if (test->safe) {
[34db7fa]1214 printf("\n");
1215 if (!run_test(test))
1216 break;
[50661ab]1217 }
1218 }
[851f33a]1219 } else if (str_cmp((char *) argv->buffer, "") != 0) {
[50661ab]1220 bool fnd = false;
1221
1222 for (test = tests; test->name != NULL; test++) {
[20cc877]1223 if (str_cmp(test->name, (char *) argv->buffer) == 0) {
[50661ab]1224 fnd = true;
[34db7fa]1225 run_test(test);
[50661ab]1226 break;
1227 }
[319e60e]1228 }
[50661ab]1229
1230 if (!fnd)
[34db7fa]1231 printf("Unknown test\n");
[851f33a]1232 } else
1233 list_tests();
[319e60e]1234
1235 return 1;
1236}
[95155b0c]1237
1238/** Command for returning kernel tests as benchmarks
1239 *
1240 * @param argv Argument vector.
1241 *
1242 * return Always 1.
1243 */
1244int cmd_bench(cmd_arg_t *argv)
1245{
1246 test_t *test;
1247 uint32_t cnt = argv[1].intval;
1248
[3f2177e]1249 if (str_cmp((char *) argv->buffer, "*") == 0) {
1250 for (test = tests; test->name != NULL; test++) {
1251 if (test->safe) {
1252 if (!run_bench(test, cnt))
1253 break;
1254 }
[95155b0c]1255 }
[3f2177e]1256 } else {
1257 bool fnd = false;
[95155b0c]1258
[3f2177e]1259 for (test = tests; test->name != NULL; test++) {
1260 if (str_cmp(test->name, (char *) argv->buffer) == 0) {
1261 fnd = true;
1262
1263 if (test->safe)
1264 run_bench(test, cnt);
1265 else
1266 printf("Unsafe test\n");
1267
1268 break;
1269 }
1270 }
1271
1272 if (!fnd)
1273 printf("Unknown test\n");
1274 }
[cb01e1e]1275
[95155b0c]1276 return 1;
1277}
1278
[50661ab]1279#endif
[319e60e]1280
[06e1e95]1281/** @}
[b45c443]1282 */
Note: See TracBrowser for help on using the repository browser.