source: mainline/kernel/generic/src/console/cmd.c@ 5d230a30

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5d230a30 was 181a746, checked in by Adam Hraska <adam.hraska+hos@…>, 13 years ago

rcu: Added preemptible RCU's core API implementation.

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