source: mainline/kernel/generic/src/console/cmd.c@ 32cd37f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 32cd37f was 55b77d9, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Separate list_t typedef from link_t (kernel part).

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