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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f571ca49 was 63e27ef, checked in by Jiri Svoboda <jiri@…>, 8 years ago

ASSERT → assert

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