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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a363016 was a363016, checked in by Aurelio Colosimo <aurelio@…>, 9 years ago

kconsole tab completion: call* argument hints restored by using proper callback

  • Property mode set to 100644
File size: 35.0 KB
Line 
1/*
2 * Copyright (c) 2005 Jakub Jermar
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
29/** @addtogroup genericconsole
30 * @{
31 */
32
33/**
34 * @file cmd.c
35 * @brief Kernel console command wrappers.
36 *
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>
44#include <console/console.h>
45#include <console/kconsole.h>
46#include <print.h>
47#include <log.h>
48#include <panic.h>
49#include <typedefs.h>
50#include <adt/list.h>
51#include <arch.h>
52#include <config.h>
53#include <func.h>
54#include <str.h>
55#include <macros.h>
56#include <debug.h>
57#include <cpu.h>
58#include <mm/tlb.h>
59#include <mm/km.h>
60#include <arch/mm/tlb.h>
61#include <mm/frame.h>
62#include <main/version.h>
63#include <mm/slab.h>
64#include <proc/scheduler.h>
65#include <proc/thread.h>
66#include <proc/task.h>
67#include <ipc/ipc.h>
68#include <ipc/irq.h>
69#include <ipc/event.h>
70#include <sysinfo/sysinfo.h>
71#include <symtab.h>
72#include <synch/workqueue.h>
73#include <synch/rcu.h>
74#include <errno.h>
75
76#ifdef CONFIG_TEST
77#include <test.h>
78#endif
79
80/* Data and methods for 'help' command. */
81static int cmd_help(cmd_arg_t *argv);
82static cmd_info_t help_info = {
83 .name = "help",
84 .description = "List supported commands.",
85 .func = cmd_help,
86 .argc = 0
87};
88
89/* Data and methods for pio_read_8 command */
90static int cmd_pio_read_8(cmd_arg_t *argv);
91static cmd_arg_t pio_read_8_argv[] = { { .type = ARG_TYPE_INT } };
92static cmd_info_t pio_read_8_info = {
93 .name = "pio_read_8",
94 .description = "pio_read_8 <address> Read 1 byte from memory (or port).",
95 .func = cmd_pio_read_8,
96 .argc = 1,
97 .argv = pio_read_8_argv
98};
99
100/* Data and methods for pio_read_16 command */
101static int cmd_pio_read_16(cmd_arg_t *argv);
102static cmd_arg_t pio_read_16_argv[] = { { .type = ARG_TYPE_INT } };
103static cmd_info_t pio_read_16_info = {
104 .name = "pio_read_16",
105 .description = "pio_read_16 <address> Read 2 bytes from memory (or port).",
106 .func = cmd_pio_read_16,
107 .argc = 1,
108 .argv = pio_read_16_argv
109};
110
111/* Data and methods for pio_read_32 command */
112static int cmd_pio_read_32(cmd_arg_t *argv);
113static cmd_arg_t pio_read_32_argv[] = { { .type = ARG_TYPE_INT } };
114static cmd_info_t pio_read_32_info = {
115 .name = "pio_read_32",
116 .description = "pio_read_32 <address> Read 4 bytes from memory (or port).",
117 .func = cmd_pio_read_32,
118 .argc = 1,
119 .argv = pio_read_32_argv
120};
121
122/* Data and methods for pio_write_8 command */
123static int cmd_pio_write_8(cmd_arg_t *argv);
124static cmd_arg_t pio_write_8_argv[] = {
125 { .type = ARG_TYPE_INT },
126 { .type = ARG_TYPE_INT }
127};
128static cmd_info_t pio_write_8_info = {
129 .name = "pio_write_8",
130 .description = "pio_write_8 <address> <value> Write 1 byte to memory (or port).",
131 .func = cmd_pio_write_8,
132 .argc = 2,
133 .argv = pio_write_8_argv
134};
135
136/* Data and methods for pio_write_16 command */
137static int cmd_pio_write_16(cmd_arg_t *argv);
138static cmd_arg_t pio_write_16_argv[] = {
139 { .type = ARG_TYPE_INT },
140 { .type = ARG_TYPE_INT }
141};
142static cmd_info_t pio_write_16_info = {
143 .name = "pio_write_16",
144 .description = "pio_write_16 <address> <value> Write 2 bytes to memory (or port).",
145 .func = cmd_pio_write_16,
146 .argc = 2,
147 .argv = pio_write_16_argv
148};
149
150/* Data and methods for pio_write_32 command */
151static int cmd_pio_write_32(cmd_arg_t *argv);
152static cmd_arg_t pio_write_32_argv[] = {
153 { .type = ARG_TYPE_INT },
154 { .type = ARG_TYPE_INT }
155};
156static cmd_info_t pio_write_32_info = {
157 .name = "pio_write_32",
158 .description = "pio_write_32 <address> <value> Write 4 bytes to memory (or port).",
159 .func = cmd_pio_write_32,
160 .argc = 2,
161 .argv = pio_write_32_argv
162};
163
164/* Data and methods for 'reboot' command. */
165static int cmd_reboot(cmd_arg_t *argv);
166static cmd_info_t reboot_info = {
167 .name = "reboot",
168 .description = "Reboot system.",
169 .func = cmd_reboot,
170 .argc = 0
171};
172
173/* Data and methods for 'uptime' command. */
174static int cmd_uptime(cmd_arg_t *argv);
175static cmd_info_t uptime_info = {
176 .name = "uptime",
177 .description = "Show system uptime.",
178 .func = cmd_uptime,
179 .argc = 0
180};
181
182/* Data and methods for 'continue' command. */
183static int cmd_continue(cmd_arg_t *argv);
184static cmd_info_t continue_info = {
185 .name = "continue",
186 .description = "Return console back to userspace.",
187 .func = cmd_continue,
188 .argc = 0
189};
190
191#ifdef CONFIG_TEST
192
193/* Data and methods for 'test' command. */
194static char test_buf[MAX_CMDLINE + 1];
195static int cmd_test(cmd_arg_t *argv);
196static cmd_arg_t test_argv[] = {
197 {
198 .type = ARG_TYPE_STRING_OPTIONAL,
199 .buffer = test_buf,
200 .len = sizeof(test_buf)
201 }
202};
203static cmd_info_t test_info = {
204 .name = "test",
205 .description = "<test> List kernel tests or run a test.",
206 .func = cmd_test,
207 .argc = 1,
208 .argv = test_argv
209};
210
211/* Data and methods for 'bench' command. */
212static int cmd_bench(cmd_arg_t *argv);
213static cmd_arg_t bench_argv[] = {
214 {
215 .type = ARG_TYPE_STRING,
216 .buffer = test_buf,
217 .len = sizeof(test_buf)
218 },
219 {
220 .type = ARG_TYPE_INT,
221 }
222};
223static cmd_info_t bench_info = {
224 .name = "bench",
225 .description = "<test> <count> Run kernel test as benchmark.",
226 .func = cmd_bench,
227 .argc = 2,
228 .argv = bench_argv
229};
230
231#endif /* CONFIG_TEST */
232
233/* Data and methods for 'description' command. */
234static int cmd_desc(cmd_arg_t *argv);
235static void desc_help(void);
236static char desc_buf[MAX_CMDLINE + 1];
237static cmd_arg_t desc_argv = {
238 .type = ARG_TYPE_STRING,
239 .buffer = desc_buf,
240 .len = sizeof(desc_buf)
241};
242static cmd_info_t desc_info = {
243 .name = "describe",
244 .description = "<command> Describe specified command.",
245 .help = desc_help,
246 .func = cmd_desc,
247 .argc = 1,
248 .argv = &desc_argv
249};
250
251/* Data and methods for 'symaddr' command. */
252static int cmd_symaddr(cmd_arg_t *argv);
253static char symaddr_buf[MAX_CMDLINE + 1];
254static cmd_arg_t symaddr_argv = {
255 .type = ARG_TYPE_STRING,
256 .buffer = symaddr_buf,
257 .len = sizeof(symaddr_buf)
258};
259static cmd_info_t symaddr_info = {
260 .name = "symaddr",
261 .description = "<symbol> Return symbol address.",
262 .func = cmd_symaddr,
263 .argc = 1,
264 .argv = &symaddr_argv
265};
266
267/* Data and methods for 'set4' command. */
268static char set_buf[MAX_CMDLINE + 1];
269static int cmd_set4(cmd_arg_t *argv);
270static cmd_arg_t set4_argv[] = {
271 {
272 .type = ARG_TYPE_STRING,
273 .buffer = set_buf,
274 .len = sizeof(set_buf)
275 },
276 {
277 .type = ARG_TYPE_INT
278 }
279};
280static cmd_info_t set4_info = {
281 .name = "set4",
282 .description = "<addr> <value> Set 4B memory location to a value.",
283 .func = cmd_set4,
284 .argc = 2,
285 .argv = set4_argv
286};
287
288/* Data and methods for 'call0' and 'mcall0' command. */
289static char call0_buf[MAX_CMDLINE + 1];
290static char carg1_buf[MAX_CMDLINE + 1];
291static char carg2_buf[MAX_CMDLINE + 1];
292static char carg3_buf[MAX_CMDLINE + 1];
293
294static int cmd_call0(cmd_arg_t *argv);
295static cmd_arg_t call0_argv = {
296 .type = ARG_TYPE_STRING,
297 .buffer = call0_buf,
298 .len = sizeof(call0_buf)
299};
300static cmd_info_t call0_info = {
301 .name = "call0",
302 .description = "<function> Call function().",
303 .func = cmd_call0,
304 .argc = 1,
305 .argv = &call0_argv,
306 .hints_enum = symtab_hints_enum
307};
308
309/* Data and methods for 'mcall0' command. */
310static int cmd_mcall0(cmd_arg_t *argv);
311static cmd_arg_t mcall0_argv = {
312 .type = ARG_TYPE_STRING,
313 .buffer = call0_buf,
314 .len = sizeof(call0_buf)
315};
316static cmd_info_t mcall0_info = {
317 .name = "mcall0",
318 .description = "<function> Call function() on each CPU.",
319 .func = cmd_mcall0,
320 .argc = 1,
321 .argv = &mcall0_argv,
322 .hints_enum = symtab_hints_enum
323};
324
325/* Data and methods for 'call1' command. */
326static int cmd_call1(cmd_arg_t *argv);
327static cmd_arg_t call1_argv[] = {
328 {
329 .type = ARG_TYPE_STRING,
330 .buffer = call0_buf,
331 .len = sizeof(call0_buf)
332 },
333 {
334 .type = ARG_TYPE_VAR,
335 .buffer = carg1_buf,
336 .len = sizeof(carg1_buf)
337 }
338};
339static cmd_info_t call1_info = {
340 .name = "call1",
341 .description = "<function> <arg1> Call function(arg1).",
342 .func = cmd_call1,
343 .argc = 2,
344 .argv = call1_argv,
345 .hints_enum = symtab_hints_enum
346};
347
348/* Data and methods for 'call2' command. */
349static int cmd_call2(cmd_arg_t *argv);
350static cmd_arg_t call2_argv[] = {
351 {
352 .type = ARG_TYPE_STRING,
353 .buffer = call0_buf,
354 .len = sizeof(call0_buf)
355 },
356 {
357 .type = ARG_TYPE_VAR,
358 .buffer = carg1_buf,
359 .len = sizeof(carg1_buf)
360 },
361 {
362 .type = ARG_TYPE_VAR,
363 .buffer = carg2_buf,
364 .len = sizeof(carg2_buf)
365 }
366};
367static cmd_info_t call2_info = {
368 .name = "call2",
369 .description = "<function> <arg1> <arg2> Call function(arg1, arg2).",
370 .func = cmd_call2,
371 .argc = 3,
372 .argv = call2_argv,
373 .hints_enum = symtab_hints_enum
374};
375
376/* Data and methods for 'call3' command. */
377static int cmd_call3(cmd_arg_t *argv);
378static cmd_arg_t call3_argv[] = {
379 {
380 .type = ARG_TYPE_STRING,
381 .buffer = call0_buf,
382 .len = sizeof(call0_buf)
383 },
384 {
385 .type = ARG_TYPE_VAR,
386 .buffer = carg1_buf,
387 .len = sizeof(carg1_buf)
388 },
389 {
390 .type = ARG_TYPE_VAR,
391 .buffer = carg2_buf,
392 .len = sizeof(carg2_buf)
393 },
394 {
395 .type = ARG_TYPE_VAR,
396 .buffer = carg3_buf,
397 .len = sizeof(carg3_buf)
398 }
399
400};
401static cmd_info_t call3_info = {
402 .name = "call3",
403 .description = "<function> <arg1> <arg2> <arg3> Call function(arg1, arg2, arg3).",
404 .func = cmd_call3,
405 .argc = 4,
406 .argv = call3_argv,
407 .hints_enum = symtab_hints_enum
408};
409
410/* Data and methods for 'halt' command. */
411static int cmd_halt(cmd_arg_t *argv);
412static cmd_info_t halt_info = {
413 .name = "halt",
414 .description = "Halt the kernel.",
415 .func = cmd_halt,
416 .argc = 0
417};
418
419/* Data and methods for 'physmem' command. */
420static int cmd_physmem(cmd_arg_t *argv);
421cmd_info_t physmem_info = {
422 .name = "physmem",
423 .description = "Print physical memory configuration.",
424 .help = NULL,
425 .func = cmd_physmem,
426 .argc = 0,
427 .argv = NULL
428};
429
430/* Data and methods for 'tlb' command. */
431static int cmd_tlb(cmd_arg_t *argv);
432cmd_info_t tlb_info = {
433 .name = "tlb",
434 .description = "Print TLB of the current CPU.",
435 .help = NULL,
436 .func = cmd_tlb,
437 .argc = 0,
438 .argv = NULL
439};
440
441static char flag_buf[MAX_CMDLINE + 1];
442
443static int cmd_threads(cmd_arg_t *argv);
444static cmd_arg_t threads_argv = {
445 .type = ARG_TYPE_STRING_OPTIONAL,
446 .buffer = flag_buf,
447 .len = sizeof(flag_buf)
448};
449static cmd_info_t threads_info = {
450 .name = "threads",
451 .description = "List all threads (use -a for additional information).",
452 .func = cmd_threads,
453 .argc = 1,
454 .argv = &threads_argv
455};
456
457static int cmd_tasks(cmd_arg_t *argv);
458static cmd_arg_t tasks_argv = {
459 .type = ARG_TYPE_STRING_OPTIONAL,
460 .buffer = flag_buf,
461 .len = sizeof(flag_buf)
462};
463static cmd_info_t tasks_info = {
464 .name = "tasks",
465 .description = "List all tasks (use -a for additional information).",
466 .func = cmd_tasks,
467 .argc = 1,
468 .argv = &tasks_argv
469};
470
471#ifdef CONFIG_UDEBUG
472
473/* Data and methods for 'btrace' command */
474static int cmd_btrace(cmd_arg_t *argv);
475static cmd_arg_t btrace_argv = {
476 .type = ARG_TYPE_INT,
477};
478static cmd_info_t btrace_info = {
479 .name = "btrace",
480 .description = "<threadid> Show thread stack trace.",
481 .func = cmd_btrace,
482 .argc = 1,
483 .argv = &btrace_argv
484};
485
486#endif /* CONFIG_UDEBUG */
487
488static int cmd_sched(cmd_arg_t *argv);
489static cmd_info_t sched_info = {
490 .name = "scheduler",
491 .description = "Show scheduler information.",
492 .func = cmd_sched,
493 .argc = 0
494};
495
496static int cmd_slabs(cmd_arg_t *argv);
497static cmd_info_t slabs_info = {
498 .name = "slabs",
499 .description = "List slab caches.",
500 .func = cmd_slabs,
501 .argc = 0
502};
503
504static int cmd_sysinfo(cmd_arg_t *argv);
505static cmd_info_t sysinfo_info = {
506 .name = "sysinfo",
507 .description = "Dump sysinfo.",
508 .func = cmd_sysinfo,
509 .argc = 0
510};
511
512/* Data and methods for 'zones' command */
513static int cmd_zones(cmd_arg_t *argv);
514static cmd_info_t zones_info = {
515 .name = "zones",
516 .description = "List memory zones.",
517 .func = cmd_zones,
518 .argc = 0
519};
520
521/* Data and methods for 'zone' command */
522static int cmd_zone(cmd_arg_t *argv);
523static cmd_arg_t zone_argv = {
524 .type = ARG_TYPE_INT,
525};
526
527static cmd_info_t zone_info = {
528 .name = "zone",
529 .description = "<zone> Show memory zone structure.",
530 .func = cmd_zone,
531 .argc = 1,
532 .argv = &zone_argv
533};
534
535/* Data and methods for the 'workq' command */
536static int cmd_workq(cmd_arg_t *argv);
537static cmd_info_t workq_info = {
538 .name = "workq",
539 .description = "Show global workq information.",
540 .func = cmd_workq,
541 .argc = 0
542};
543
544/* Data and methods for the 'workq' command */
545static int cmd_rcu(cmd_arg_t *argv);
546static cmd_info_t rcu_info = {
547 .name = "rcu",
548 .description = "Show RCU run-time statistics.",
549 .func = cmd_rcu,
550 .argc = 0
551};
552
553/* Data and methods for 'ipc' command */
554static int cmd_ipc(cmd_arg_t *argv);
555static cmd_arg_t ipc_argv = {
556 .type = ARG_TYPE_INT,
557};
558static cmd_info_t ipc_info = {
559 .name = "ipc",
560 .description = "<taskid> Show IPC information of a task.",
561 .func = cmd_ipc,
562 .argc = 1,
563 .argv = &ipc_argv
564};
565
566/* Data and methods for 'kill' command */
567static int cmd_kill(cmd_arg_t *argv);
568static cmd_arg_t kill_argv = {
569 .type = ARG_TYPE_INT,
570};
571static cmd_info_t kill_info = {
572 .name = "kill",
573 .description = "<taskid> Kill a task.",
574 .func = cmd_kill,
575 .argc = 1,
576 .argv = &kill_argv
577};
578
579/* Data and methods for 'cpus' command. */
580static int cmd_cpus(cmd_arg_t *argv);
581cmd_info_t cpus_info = {
582 .name = "cpus",
583 .description = "List all processors.",
584 .help = NULL,
585 .func = cmd_cpus,
586 .argc = 0,
587 .argv = NULL
588};
589
590/* Data and methods for 'version' command. */
591static int cmd_version(cmd_arg_t *argv);
592cmd_info_t version_info = {
593 .name = "version",
594 .description = "Print version information.",
595 .help = NULL,
596 .func = cmd_version,
597 .argc = 0,
598 .argv = NULL
599};
600
601static cmd_info_t *basic_commands[] = {
602 &call0_info,
603 &mcall0_info,
604 &call1_info,
605 &call2_info,
606 &call3_info,
607 &continue_info,
608 &cpus_info,
609 &desc_info,
610 &halt_info,
611 &help_info,
612 &ipc_info,
613 &kill_info,
614 &physmem_info,
615 &reboot_info,
616 &rcu_info,
617 &sched_info,
618 &set4_info,
619 &slabs_info,
620 &symaddr_info,
621 &sysinfo_info,
622 &tasks_info,
623 &threads_info,
624 &tlb_info,
625 &uptime_info,
626 &version_info,
627 &workq_info,
628 &zones_info,
629 &zone_info,
630#ifdef CONFIG_TEST
631 &test_info,
632 &bench_info,
633#endif
634#ifdef CONFIG_UDEBUG
635 &btrace_info,
636#endif
637 &pio_read_8_info,
638 &pio_read_16_info,
639 &pio_read_32_info,
640 &pio_write_8_info,
641 &pio_write_16_info,
642 &pio_write_32_info,
643 NULL
644};
645
646
647/** Initialize command info structure.
648 *
649 * @param cmd Command info structure.
650 *
651 */
652void cmd_initialize(cmd_info_t *cmd)
653{
654 spinlock_initialize(&cmd->lock, "cmd.lock");
655 link_initialize(&cmd->link);
656}
657
658/** Initialize and register commands. */
659void cmd_init(void)
660{
661 unsigned int i;
662
663 for (i = 0; basic_commands[i]; i++) {
664 cmd_initialize(basic_commands[i]);
665 }
666
667 for (i = 0; basic_commands[i]; i++) {
668 if (!cmd_register(basic_commands[i])) {
669 log(LF_OTHER, LVL_ERROR,
670 "Cannot register command %s",
671 basic_commands[i]->name);
672 }
673 }
674}
675
676/** List supported commands.
677 *
678 * @param argv Argument vector.
679 *
680 * @return 0 on failure, 1 on success.
681 */
682int cmd_help(cmd_arg_t *argv)
683{
684 spinlock_lock(&cmd_lock);
685
686 size_t len = 0;
687 list_foreach(cmd_list, link, cmd_info_t, hlp) {
688 spinlock_lock(&hlp->lock);
689 if (str_length(hlp->name) > len)
690 len = str_length(hlp->name);
691 spinlock_unlock(&hlp->lock);
692 }
693
694 unsigned int _len = (unsigned int) len;
695 if ((_len != len) || (((int) _len) < 0)) {
696 log(LF_OTHER, LVL_ERROR, "Command length overflow");
697 return 1;
698 }
699
700 list_foreach(cmd_list, link, cmd_info_t, hlp) {
701 spinlock_lock(&hlp->lock);
702 printf("%-*s %s\n", _len, hlp->name, hlp->description);
703 spinlock_unlock(&hlp->lock);
704 }
705
706 spinlock_unlock(&cmd_lock);
707
708 return 1;
709}
710
711/** Read 1 byte from phys memory or io port.
712 *
713 * @param argv Argument vector.
714 *
715 * @return 0 on failure, 1 on success.
716 */
717static int cmd_pio_read_8(cmd_arg_t *argv)
718{
719 uint8_t *ptr = NULL;
720
721#ifdef IO_SPACE_BOUNDARY
722 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
723 ptr = (void *) argv[0].intval;
724 else
725#endif
726 ptr = (uint8_t *) km_map(argv[0].intval, sizeof(uint8_t),
727 PAGE_NOT_CACHEABLE);
728
729 const uint8_t val = pio_read_8(ptr);
730 printf("read %" PRIxn ": %" PRIx8 "\n", argv[0].intval, val);
731
732#ifdef IO_SPACE_BOUNDARY
733 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
734 return 1;
735#endif
736
737 km_unmap((uintptr_t) ptr, sizeof(uint8_t));
738 return 1;
739}
740
741/** Read 2 bytes from phys memory or io port.
742 *
743 * @param argv Argument vector.
744 *
745 * @return 0 on failure, 1 on success.
746 */
747static int cmd_pio_read_16(cmd_arg_t *argv)
748{
749 uint16_t *ptr = NULL;
750
751#ifdef IO_SPACE_BOUNDARY
752 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
753 ptr = (void *) argv[0].intval;
754 else
755#endif
756 ptr = (uint16_t *) km_map(argv[0].intval, sizeof(uint16_t),
757 PAGE_NOT_CACHEABLE);
758
759 const uint16_t val = pio_read_16(ptr);
760 printf("read %" PRIxn ": %" PRIx16 "\n", argv[0].intval, val);
761
762#ifdef IO_SPACE_BOUNDARY
763 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
764 return 1;
765#endif
766
767 km_unmap((uintptr_t) ptr, sizeof(uint16_t));
768 return 1;
769}
770
771/** Read 4 bytes from phys memory or io port.
772 *
773 * @param argv Argument vector.
774 *
775 * @return 0 on failure, 1 on success.
776 */
777static int cmd_pio_read_32(cmd_arg_t *argv)
778{
779 uint32_t *ptr = NULL;
780
781#ifdef IO_SPACE_BOUNDARY
782 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
783 ptr = (void *) argv[0].intval;
784 else
785#endif
786 ptr = (uint32_t *) km_map(argv[0].intval, sizeof(uint32_t),
787 PAGE_NOT_CACHEABLE);
788
789 const uint32_t val = pio_read_32(ptr);
790 printf("read %" PRIxn ": %" PRIx32 "\n", argv[0].intval, val);
791
792#ifdef IO_SPACE_BOUNDARY
793 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
794 return 1;
795#endif
796
797 km_unmap((uintptr_t) ptr, sizeof(uint32_t));
798 return 1;
799}
800
801/** Write 1 byte to phys memory or io port.
802 *
803 * @param argv Argument vector.
804 *
805 * @return 0 on failure, 1 on success.
806 */
807static int cmd_pio_write_8(cmd_arg_t *argv)
808{
809 uint8_t *ptr = NULL;
810
811#ifdef IO_SPACE_BOUNDARY
812 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
813 ptr = (void *) argv[0].intval;
814 else
815#endif
816 ptr = (uint8_t *) km_map(argv[0].intval, sizeof(uint8_t),
817 PAGE_NOT_CACHEABLE);
818
819 printf("write %" PRIxn ": %" PRIx8 "\n", argv[0].intval,
820 (uint8_t) argv[1].intval);
821 pio_write_8(ptr, (uint8_t) argv[1].intval);
822
823#ifdef IO_SPACE_BOUNDARY
824 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
825 return 1;
826#endif
827
828 km_unmap((uintptr_t) ptr, sizeof(uint8_t));
829 return 1;
830}
831
832/** Write 2 bytes to phys memory or io port.
833 *
834 * @param argv Argument vector.
835 *
836 * @return 0 on failure, 1 on success.
837 */
838static int cmd_pio_write_16(cmd_arg_t *argv)
839{
840 uint16_t *ptr = NULL;
841
842#ifdef IO_SPACE_BOUNDARY
843 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
844 ptr = (void *) argv[0].intval;
845 else
846#endif
847 ptr = (uint16_t *) km_map(argv[0].intval, sizeof(uint16_t),
848 PAGE_NOT_CACHEABLE);
849
850 printf("write %" PRIxn ": %" PRIx16 "\n", argv[0].intval,
851 (uint16_t) argv[1].intval);
852 pio_write_16(ptr, (uint16_t) argv[1].intval);
853
854#ifdef IO_SPACE_BOUNDARY
855 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
856 return 1;
857#endif
858
859 km_unmap((uintptr_t) ptr, sizeof(uint16_t));
860 return 1;
861}
862
863/** Write 4 bytes to phys memory or io port.
864 *
865 * @param argv Argument vector.
866 *
867 * @return 0 on failure, 1 on success.
868 */
869static int cmd_pio_write_32(cmd_arg_t *argv)
870{
871 uint32_t *ptr = NULL;
872
873#ifdef IO_SPACE_BOUNDARY
874 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
875 ptr = (void *) argv[0].intval;
876 else
877#endif
878 ptr = (uint32_t *) km_map(argv[0].intval, sizeof(uint32_t),
879 PAGE_NOT_CACHEABLE);
880
881 printf("write %" PRIxn ": %" PRIx32 "\n", argv[0].intval,
882 (uint32_t) argv[1].intval);
883 pio_write_32(ptr, (uint32_t) argv[1].intval);
884
885#ifdef IO_SPACE_BOUNDARY
886 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
887 return 1;
888#endif
889
890 km_unmap((uintptr_t) ptr, sizeof(uint32_t));
891 return 1;
892}
893
894/** Reboot the system.
895 *
896 * @param argv Argument vector.
897 *
898 * @return 0 on failure, 1 on success.
899 */
900int cmd_reboot(cmd_arg_t *argv)
901{
902 reboot();
903
904 /* Not reached */
905 return 1;
906}
907
908/** Print system uptime information.
909 *
910 * @param argv Argument vector.
911 *
912 * @return 0 on failure, 1 on success.
913 */
914int cmd_uptime(cmd_arg_t *argv)
915{
916 ASSERT(uptime);
917
918 /* This doesn't have to be very accurate */
919 sysarg_t sec = uptime->seconds1;
920
921 printf("Up %" PRIun " days, %" PRIun " hours, %" PRIun " minutes, %" PRIun " seconds\n",
922 sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
923
924 return 1;
925}
926
927/** Describe specified command.
928 *
929 * @param argv Argument vector.
930 *
931 * @return 0 on failure, 1 on success.
932 */
933int cmd_desc(cmd_arg_t *argv)
934{
935 spinlock_lock(&cmd_lock);
936
937 list_foreach(cmd_list, link, cmd_info_t, hlp) {
938 spinlock_lock(&hlp->lock);
939
940 if (str_lcmp(hlp->name, (const char *) argv->buffer, str_length(hlp->name)) == 0) {
941 printf("%s - %s\n", hlp->name, hlp->description);
942 if (hlp->help)
943 hlp->help();
944 spinlock_unlock(&hlp->lock);
945 break;
946 }
947
948 spinlock_unlock(&hlp->lock);
949 }
950
951 spinlock_unlock(&cmd_lock);
952
953 return 1;
954}
955
956/** Search symbol table */
957int cmd_symaddr(cmd_arg_t *argv)
958{
959 symtab_print_search((char *) argv->buffer);
960
961 return 1;
962}
963
964/** Call function with zero parameters */
965int cmd_call0(cmd_arg_t *argv)
966{
967 uintptr_t symaddr;
968 char *symbol;
969 sysarg_t (*fnc)(void);
970 fncptr_t fptr;
971 int rc;
972
973 symbol = (char *) argv->buffer;
974 rc = symtab_addr_lookup(symbol, &symaddr);
975
976 if (rc == ENOENT)
977 printf("Symbol %s not found.\n", symbol);
978 else if (rc == EOVERFLOW) {
979 symtab_print_search(symbol);
980 printf("Duplicate symbol, be more specific.\n");
981 } else if (rc == EOK) {
982 ipl_t ipl;
983
984 ipl = interrupts_disable();
985 fnc = (sysarg_t (*)(void)) arch_construct_function(&fptr,
986 (void *) symaddr, (void *) cmd_call0);
987 printf("Calling %s() (%p)\n", symbol, (void *) symaddr);
988 printf("Result: %#" PRIxn "\n", fnc());
989 interrupts_restore(ipl);
990 } else {
991 printf("No symbol information available.\n");
992 }
993 return 1;
994}
995
996/** Call function with zero parameters on each CPU */
997int cmd_mcall0(cmd_arg_t *argv)
998{
999 /*
1000 * For each CPU, create a thread which will
1001 * call the function.
1002 */
1003
1004 unsigned int i;
1005 for (i = 0; i < config.cpu_count; i++) {
1006 if (!cpus[i].active)
1007 continue;
1008
1009 thread_t *thread;
1010 if ((thread = thread_create((void (*)(void *)) cmd_call0,
1011 (void *) argv, TASK, THREAD_FLAG_NONE, "call0"))) {
1012 printf("cpu%u: ", i);
1013 thread_wire(thread, &cpus[i]);
1014 thread_ready(thread);
1015 thread_join(thread);
1016 thread_detach(thread);
1017 } else
1018 printf("Unable to create thread for cpu%u\n", i);
1019 }
1020
1021 return 1;
1022}
1023
1024/** Call function with one parameter */
1025int cmd_call1(cmd_arg_t *argv)
1026{
1027 uintptr_t symaddr;
1028 char *symbol;
1029 sysarg_t (*fnc)(sysarg_t, ...);
1030 sysarg_t arg1 = argv[1].intval;
1031 fncptr_t fptr;
1032 int rc;
1033
1034 symbol = (char *) argv->buffer;
1035 rc = symtab_addr_lookup(symbol, &symaddr);
1036
1037 if (rc == ENOENT) {
1038 printf("Symbol %s not found.\n", symbol);
1039 } else if (rc == EOVERFLOW) {
1040 symtab_print_search(symbol);
1041 printf("Duplicate symbol, be more specific.\n");
1042 } else if (rc == EOK) {
1043 ipl_t ipl;
1044
1045 ipl = interrupts_disable();
1046 fnc = (sysarg_t (*)(sysarg_t, ...))
1047 arch_construct_function(&fptr, (void *) symaddr,
1048 (void *) cmd_call1);
1049 printf("Calling f(%#" PRIxn "): %p: %s\n", arg1,
1050 (void *) symaddr, symbol);
1051 printf("Result: %#" PRIxn "\n", fnc(arg1));
1052 interrupts_restore(ipl);
1053 } else {
1054 printf("No symbol information available.\n");
1055 }
1056
1057 return 1;
1058}
1059
1060/** Call function with two parameters */
1061int cmd_call2(cmd_arg_t *argv)
1062{
1063 uintptr_t symaddr;
1064 char *symbol;
1065 sysarg_t (*fnc)(sysarg_t, sysarg_t, ...);
1066 sysarg_t arg1 = argv[1].intval;
1067 sysarg_t arg2 = argv[2].intval;
1068 fncptr_t fptr;
1069 int rc;
1070
1071 symbol = (char *) argv->buffer;
1072 rc = symtab_addr_lookup(symbol, &symaddr);
1073
1074 if (rc == ENOENT) {
1075 printf("Symbol %s not found.\n", symbol);
1076 } else if (rc == EOVERFLOW) {
1077 symtab_print_search(symbol);
1078 printf("Duplicate symbol, be more specific.\n");
1079 } else if (rc == EOK) {
1080 ipl_t ipl;
1081
1082 ipl = interrupts_disable();
1083 fnc = (sysarg_t (*)(sysarg_t, sysarg_t, ...))
1084 arch_construct_function(&fptr, (void *) symaddr,
1085 (void *) cmd_call2);
1086 printf("Calling f(%#" PRIxn ", %#" PRIxn "): %p: %s\n",
1087 arg1, arg2, (void *) symaddr, symbol);
1088 printf("Result: %#" PRIxn "\n", fnc(arg1, arg2));
1089 interrupts_restore(ipl);
1090 } else {
1091 printf("No symbol information available.\n");
1092 }
1093 return 1;
1094}
1095
1096/** Call function with three parameters */
1097int cmd_call3(cmd_arg_t *argv)
1098{
1099 uintptr_t symaddr;
1100 char *symbol;
1101 sysarg_t (*fnc)(sysarg_t, sysarg_t, sysarg_t, ...);
1102 sysarg_t arg1 = argv[1].intval;
1103 sysarg_t arg2 = argv[2].intval;
1104 sysarg_t arg3 = argv[3].intval;
1105 fncptr_t fptr;
1106 int rc;
1107
1108 symbol = (char *) argv->buffer;
1109 rc = symtab_addr_lookup(symbol, &symaddr);
1110
1111 if (rc == ENOENT) {
1112 printf("Symbol %s not found.\n", symbol);
1113 } else if (rc == EOVERFLOW) {
1114 symtab_print_search(symbol);
1115 printf("Duplicate symbol, be more specific.\n");
1116 } else if (rc == EOK) {
1117 ipl_t ipl;
1118
1119 ipl = interrupts_disable();
1120 fnc = (sysarg_t (*)(sysarg_t, sysarg_t, sysarg_t, ...))
1121 arch_construct_function(&fptr, (void *) symaddr,
1122 (void *) cmd_call3);
1123 printf("Calling f(%#" PRIxn ",%#" PRIxn ", %#" PRIxn "): %p: %s\n",
1124 arg1, arg2, arg3, (void *) symaddr, symbol);
1125 printf("Result: %#" PRIxn "\n", fnc(arg1, arg2, arg3));
1126 interrupts_restore(ipl);
1127 } else {
1128 printf("No symbol information available.\n");
1129 }
1130 return 1;
1131}
1132
1133/** Print detailed description of 'describe' command. */
1134void desc_help(void)
1135{
1136 printf("Syntax: describe command_name\n");
1137}
1138
1139/** Halt the kernel.
1140 *
1141 * @param argv Argument vector (ignored).
1142 *
1143 * @return 0 on failure, 1 on success (never returns).
1144 */
1145int cmd_halt(cmd_arg_t *argv)
1146{
1147 halt();
1148 return 1;
1149}
1150
1151/** Command for printing TLB contents.
1152 *
1153 * @param argv Not used.
1154 *
1155 * @return Always returns 1.
1156 */
1157int cmd_tlb(cmd_arg_t *argv)
1158{
1159 tlb_print();
1160 return 1;
1161}
1162
1163/** Command for printing physical memory configuration.
1164 *
1165 * @param argv Not used.
1166 *
1167 * @return Always returns 1.
1168 */
1169int cmd_physmem(cmd_arg_t *argv)
1170{
1171 physmem_print();
1172 return 1;
1173}
1174
1175/** Write 4 byte value to address */
1176int cmd_set4(cmd_arg_t *argv)
1177{
1178 uintptr_t addr = 0; // Prevent -Werror=maybe-uninitialized
1179 uint32_t arg1 = argv[1].intval;
1180 bool pointer = false;
1181 int rc;
1182
1183 if (((char *) argv->buffer)[0] == '*') {
1184 rc = symtab_addr_lookup((char *) argv->buffer + 1, &addr);
1185 pointer = true;
1186 } else if (((char *) argv->buffer)[0] >= '0' &&
1187 ((char *) argv->buffer)[0] <= '9') {
1188 uint64_t value;
1189 rc = str_uint64_t((char *) argv->buffer, NULL, 0, true, &value);
1190 if (rc == EOK)
1191 addr = (uintptr_t) value;
1192 } else
1193 rc = symtab_addr_lookup((char *) argv->buffer, &addr);
1194
1195 if (rc == ENOENT)
1196 printf("Symbol %s not found.\n", (char *) argv->buffer);
1197 else if (rc == EINVAL)
1198 printf("Invalid address.\n");
1199 else if (rc == EOVERFLOW) {
1200 symtab_print_search((char *) argv->buffer);
1201 printf("Duplicate symbol (be more specific) or address overflow.\n");
1202 } else if (rc == EOK) {
1203 if (pointer)
1204 addr = *(uintptr_t *) addr;
1205 printf("Writing %#" PRIx32" -> %p\n", arg1, (void *) addr);
1206 *(uint32_t *) addr = arg1;
1207 } else
1208 printf("No symbol information available.\n");
1209
1210 return 1;
1211}
1212
1213/** Command for listings SLAB caches
1214 *
1215 * @param argv Ignores
1216 *
1217 * @return Always 1
1218 */
1219int cmd_slabs(cmd_arg_t *argv)
1220{
1221 slab_print_list();
1222 return 1;
1223}
1224
1225/** Command for dumping sysinfo
1226 *
1227 * @param argv Ignores
1228 *
1229 * @return Always 1
1230 */
1231int cmd_sysinfo(cmd_arg_t *argv)
1232{
1233 sysinfo_dump(NULL);
1234 return 1;
1235}
1236
1237/** Command for listing thread information
1238 *
1239 * @param argv Ignored
1240 *
1241 * @return Always 1
1242 */
1243int cmd_threads(cmd_arg_t *argv)
1244{
1245 if (str_cmp(flag_buf, "-a") == 0)
1246 thread_print_list(true);
1247 else if (str_cmp(flag_buf, "") == 0)
1248 thread_print_list(false);
1249 else
1250 printf("Unknown argument \"%s\".\n", flag_buf);
1251
1252 return 1;
1253}
1254
1255/** Command for listing task information
1256 *
1257 * @param argv Ignored
1258 *
1259 * @return Always 1
1260 */
1261int cmd_tasks(cmd_arg_t *argv)
1262{
1263 if (str_cmp(flag_buf, "-a") == 0)
1264 task_print_list(true);
1265 else if (str_cmp(flag_buf, "") == 0)
1266 task_print_list(false);
1267 else
1268 printf("Unknown argument \"%s\".\n", flag_buf);
1269
1270 return 1;
1271}
1272
1273#ifdef CONFIG_UDEBUG
1274
1275/** Command for printing thread stack trace
1276 *
1277 * @param argv Integer argument from cmdline expected
1278 *
1279 * return Always 1
1280 *
1281 */
1282int cmd_btrace(cmd_arg_t *argv)
1283{
1284 thread_stack_trace(argv[0].intval);
1285 return 1;
1286}
1287
1288#endif /* CONFIG_UDEBUG */
1289
1290/** Command for printing scheduler information
1291 *
1292 * @param argv Ignores
1293 *
1294 * @return Always 1
1295 */
1296int cmd_sched(cmd_arg_t *argv)
1297{
1298 sched_print_list();
1299 return 1;
1300}
1301
1302/** Prints information about the global work queue.
1303 *
1304 * @param argv Ignores
1305 *
1306 * @return Always 1
1307 */
1308int cmd_workq(cmd_arg_t *argv)
1309{
1310 workq_global_print_info();
1311 return 1;
1312}
1313
1314/** Prints RCU statistics.
1315 *
1316 * @param argv Ignores
1317 *
1318 * @return Always 1
1319 */
1320int cmd_rcu(cmd_arg_t *argv)
1321{
1322 rcu_print_stat();
1323 return 1;
1324}
1325
1326/** Command for listing memory zones
1327 *
1328 * @param argv Ignored
1329 *
1330 * return Always 1
1331 */
1332int cmd_zones(cmd_arg_t *argv)
1333{
1334 zones_print_list();
1335 return 1;
1336}
1337
1338/** Command for memory zone details
1339 *
1340 * @param argv Integer argument from cmdline expected
1341 *
1342 * return Always 1
1343 */
1344int cmd_zone(cmd_arg_t *argv)
1345{
1346 zone_print_one(argv[0].intval);
1347 return 1;
1348}
1349
1350/** Command for printing task IPC details
1351 *
1352 * @param argv Integer argument from cmdline expected
1353 *
1354 * return Always 1
1355 */
1356int cmd_ipc(cmd_arg_t *argv)
1357{
1358 ipc_print_task(argv[0].intval);
1359 return 1;
1360}
1361
1362/** Command for killing a task
1363 *
1364 * @param argv Integer argument from cmdline expected
1365 *
1366 * return 0 on failure, 1 on success.
1367 */
1368int cmd_kill(cmd_arg_t *argv)
1369{
1370 if (task_kill(argv[0].intval) != EOK)
1371 return 0;
1372
1373 return 1;
1374}
1375
1376/** Command for listing processors.
1377 *
1378 * @param argv Ignored.
1379 *
1380 * return Always 1.
1381 */
1382int cmd_cpus(cmd_arg_t *argv)
1383{
1384 cpu_list();
1385 return 1;
1386}
1387
1388/** Command for printing kernel version.
1389 *
1390 * @param argv Ignored.
1391 *
1392 * return Always 1.
1393 */
1394int cmd_version(cmd_arg_t *argv)
1395{
1396 version_print();
1397 return 1;
1398}
1399
1400/** Command for returning console back to userspace.
1401 *
1402 * @param argv Ignored.
1403 *
1404 * return Always 1.
1405 */
1406int cmd_continue(cmd_arg_t *argv)
1407{
1408 printf("The kernel will now relinquish the console.\n");
1409 release_console();
1410 indev_pop_character(stdin);
1411
1412 return 1;
1413}
1414
1415#ifdef CONFIG_TEST
1416static bool run_test(const test_t *test)
1417{
1418 printf("%s (%s)\n", test->name, test->desc);
1419
1420 /* Update and read thread accounting
1421 for benchmarking */
1422 irq_spinlock_lock(&TASK->lock, true);
1423 uint64_t ucycles0, kcycles0;
1424 task_get_accounting(TASK, &ucycles0, &kcycles0);
1425 irq_spinlock_unlock(&TASK->lock, true);
1426
1427 /* Execute the test */
1428 test_quiet = false;
1429 const char *ret = test->entry();
1430
1431 /* Update and read thread accounting */
1432 uint64_t ucycles1, kcycles1;
1433 irq_spinlock_lock(&TASK->lock, true);
1434 task_get_accounting(TASK, &ucycles1, &kcycles1);
1435 irq_spinlock_unlock(&TASK->lock, true);
1436
1437 uint64_t ucycles, kcycles;
1438 char usuffix, ksuffix;
1439 order_suffix(ucycles1 - ucycles0, &ucycles, &usuffix);
1440 order_suffix(kcycles1 - kcycles0, &kcycles, &ksuffix);
1441
1442 printf("Time: %" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles\n",
1443 ucycles, usuffix, kcycles, ksuffix);
1444
1445 if (ret == NULL) {
1446 printf("Test passed\n");
1447 return true;
1448 }
1449
1450 printf("%s\n", ret);
1451 return false;
1452}
1453
1454static bool run_bench(const test_t *test, const uint32_t cnt)
1455{
1456 uint32_t i;
1457 bool ret = true;
1458 uint64_t ucycles, kcycles;
1459 char usuffix, ksuffix;
1460
1461 if (cnt < 1)
1462 return true;
1463
1464 uint64_t *data = (uint64_t *) malloc(sizeof(uint64_t) * cnt, 0);
1465 if (data == NULL) {
1466 printf("Error allocating memory for statistics\n");
1467 return false;
1468 }
1469
1470 for (i = 0; i < cnt; i++) {
1471 printf("%s (%u/%u) ... ", test->name, i + 1, cnt);
1472
1473 /* Update and read thread accounting
1474 for benchmarking */
1475 irq_spinlock_lock(&TASK->lock, true);
1476 uint64_t ucycles0, kcycles0;
1477 task_get_accounting(TASK, &ucycles0, &kcycles0);
1478 irq_spinlock_unlock(&TASK->lock, true);
1479
1480 /* Execute the test */
1481 test_quiet = true;
1482 const char *test_ret = test->entry();
1483
1484 /* Update and read thread accounting */
1485 irq_spinlock_lock(&TASK->lock, true);
1486 uint64_t ucycles1, kcycles1;
1487 task_get_accounting(TASK, &ucycles1, &kcycles1);
1488 irq_spinlock_unlock(&TASK->lock, true);
1489
1490 if (test_ret != NULL) {
1491 printf("%s\n", test_ret);
1492 ret = false;
1493 break;
1494 }
1495
1496 data[i] = ucycles1 - ucycles0 + kcycles1 - kcycles0;
1497 order_suffix(ucycles1 - ucycles0, &ucycles, &usuffix);
1498 order_suffix(kcycles1 - kcycles0, &kcycles, &ksuffix);
1499 printf("OK (%" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles)\n",
1500 ucycles, usuffix, kcycles, ksuffix);
1501 }
1502
1503 if (ret) {
1504 printf("\n");
1505
1506 uint64_t sum = 0;
1507
1508 for (i = 0; i < cnt; i++) {
1509 sum += data[i];
1510 }
1511
1512 order_suffix(sum / (uint64_t) cnt, &ucycles, &usuffix);
1513 printf("Average\t\t%" PRIu64 "%c\n", ucycles, usuffix);
1514 }
1515
1516 free(data);
1517
1518 return ret;
1519}
1520
1521static void list_tests(void)
1522{
1523 size_t len = 0;
1524 test_t *test;
1525
1526 for (test = tests; test->name != NULL; test++) {
1527 if (str_length(test->name) > len)
1528 len = str_length(test->name);
1529 }
1530
1531 unsigned int _len = (unsigned int) len;
1532 if ((_len != len) || (((int) _len) < 0)) {
1533 printf("Command length overflow\n");
1534 return;
1535 }
1536
1537 for (test = tests; test->name != NULL; test++)
1538 printf("%-*s %s%s\n", _len, test->name, test->desc,
1539 (test->safe ? "" : " (unsafe)"));
1540
1541 printf("%-*s Run all safe tests\n", _len, "*");
1542}
1543
1544/** Command for listing and running kernel tests
1545 *
1546 * @param argv Argument vector.
1547 *
1548 * return Always 1.
1549 *
1550 */
1551int cmd_test(cmd_arg_t *argv)
1552{
1553 test_t *test;
1554
1555 if (str_cmp((char *) argv->buffer, "*") == 0) {
1556 for (test = tests; test->name != NULL; test++) {
1557 if (test->safe) {
1558 printf("\n");
1559 if (!run_test(test))
1560 break;
1561 }
1562 }
1563 } else if (str_cmp((char *) argv->buffer, "") != 0) {
1564 bool fnd = false;
1565
1566 for (test = tests; test->name != NULL; test++) {
1567 if (str_cmp(test->name, (char *) argv->buffer) == 0) {
1568 fnd = true;
1569 run_test(test);
1570 break;
1571 }
1572 }
1573
1574 if (!fnd)
1575 printf("Unknown test\n");
1576 } else
1577 list_tests();
1578
1579 return 1;
1580}
1581
1582/** Command for returning kernel tests as benchmarks
1583 *
1584 * @param argv Argument vector.
1585 *
1586 * return Always 1.
1587 */
1588int cmd_bench(cmd_arg_t *argv)
1589{
1590 test_t *test;
1591 uint32_t cnt = argv[1].intval;
1592
1593 if (str_cmp((char *) argv->buffer, "*") == 0) {
1594 for (test = tests; test->name != NULL; test++) {
1595 if (test->safe) {
1596 if (!run_bench(test, cnt))
1597 break;
1598 }
1599 }
1600 } else {
1601 bool fnd = false;
1602
1603 for (test = tests; test->name != NULL; test++) {
1604 if (str_cmp(test->name, (char *) argv->buffer) == 0) {
1605 fnd = true;
1606
1607 if (test->safe)
1608 run_bench(test, cnt);
1609 else
1610 printf("Unsafe test\n");
1611
1612 break;
1613 }
1614 }
1615
1616 if (!fnd)
1617 printf("Unknown test\n");
1618 }
1619
1620 return 1;
1621}
1622
1623#endif
1624
1625/** @}
1626 */
Note: See TracBrowser for help on using the repository browser.