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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 174156fd was 174156fd, checked in by Jakub Jermar <jakub@…>, 7 years ago

Disambiguate doxygroup generic*

  • 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 kernel_generic_console
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 <halt.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_caches(cmd_arg_t *argv);
500static cmd_info_t caches_info = {
501 .name = "caches",
502 .description = "List slab caches.",
503 .func = cmd_caches,
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 &caches_info,
608 &call1_info,
609 &call2_info,
610 &call3_info,
611 &continue_info,
612 &cpus_info,
613 &desc_info,
614 &halt_info,
615 &help_info,
616 &ipc_info,
617 &kill_info,
618 &physmem_info,
619 &reboot_info,
620 &rcu_info,
621 &sched_info,
622 &set4_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/** Initialize command info structure.
650 *
651 * @param cmd Command info structure.
652 *
653 */
654void cmd_initialize(cmd_info_t *cmd)
655{
656 spinlock_initialize(&cmd->lock, "cmd.lock");
657 link_initialize(&cmd->link);
658}
659
660/** Initialize and register commands. */
661void cmd_init(void)
662{
663 unsigned int i;
664
665 for (i = 0; basic_commands[i]; i++) {
666 cmd_initialize(basic_commands[i]);
667 }
668
669 for (i = 0; basic_commands[i]; i++) {
670 if (!cmd_register(basic_commands[i])) {
671 log(LF_OTHER, LVL_ERROR,
672 "Cannot register command %s",
673 basic_commands[i]->name);
674 }
675 }
676}
677
678/** List supported commands.
679 *
680 * @param argv Argument vector.
681 *
682 * @return 0 on failure, 1 on success.
683 */
684int cmd_help(cmd_arg_t *argv)
685{
686 spinlock_lock(&cmd_lock);
687
688 size_t len = 0;
689 list_foreach(cmd_list, link, cmd_info_t, hlp) {
690 spinlock_lock(&hlp->lock);
691 if (str_length(hlp->name) > len)
692 len = str_length(hlp->name);
693 spinlock_unlock(&hlp->lock);
694 }
695
696 unsigned int _len = (unsigned int) len;
697 if ((_len != len) || (((int) _len) < 0)) {
698 log(LF_OTHER, LVL_ERROR, "Command length overflow");
699 return 1;
700 }
701
702 list_foreach(cmd_list, link, cmd_info_t, hlp) {
703 spinlock_lock(&hlp->lock);
704 printf("%-*s %s\n", _len, hlp->name, hlp->description);
705 spinlock_unlock(&hlp->lock);
706 }
707
708 spinlock_unlock(&cmd_lock);
709
710 return 1;
711}
712
713/** Read 1 byte from phys memory or io port.
714 *
715 * @param argv Argument vector.
716 *
717 * @return 0 on failure, 1 on success.
718 */
719static int cmd_pio_read_8(cmd_arg_t *argv)
720{
721 uint8_t *ptr = NULL;
722
723#ifdef IO_SPACE_BOUNDARY
724 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
725 ptr = (void *) argv[0].intval;
726 else
727#endif
728 ptr = (uint8_t *) km_map(argv[0].intval, sizeof(uint8_t),
729 PAGE_SIZE, PAGE_NOT_CACHEABLE);
730
731 const uint8_t val = pio_read_8(ptr);
732 printf("read %" PRIxn ": %" PRIx8 "\n", argv[0].intval, val);
733
734#ifdef IO_SPACE_BOUNDARY
735 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
736 return 1;
737#endif
738
739 km_unmap((uintptr_t) ptr, sizeof(uint8_t));
740 return 1;
741}
742
743/** Read 2 bytes from phys memory or io port.
744 *
745 * @param argv Argument vector.
746 *
747 * @return 0 on failure, 1 on success.
748 */
749static int cmd_pio_read_16(cmd_arg_t *argv)
750{
751 uint16_t *ptr = NULL;
752
753#ifdef IO_SPACE_BOUNDARY
754 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
755 ptr = (void *) argv[0].intval;
756 else
757#endif
758 ptr = (uint16_t *) km_map(argv[0].intval, sizeof(uint16_t),
759 PAGE_SIZE, PAGE_NOT_CACHEABLE);
760
761 const uint16_t val = pio_read_16(ptr);
762 printf("read %" PRIxn ": %" PRIx16 "\n", argv[0].intval, val);
763
764#ifdef IO_SPACE_BOUNDARY
765 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
766 return 1;
767#endif
768
769 km_unmap((uintptr_t) ptr, sizeof(uint16_t));
770 return 1;
771}
772
773/** Read 4 bytes from phys memory or io port.
774 *
775 * @param argv Argument vector.
776 *
777 * @return 0 on failure, 1 on success.
778 */
779static int cmd_pio_read_32(cmd_arg_t *argv)
780{
781 uint32_t *ptr = NULL;
782
783#ifdef IO_SPACE_BOUNDARY
784 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
785 ptr = (void *) argv[0].intval;
786 else
787#endif
788 ptr = (uint32_t *) km_map(argv[0].intval, sizeof(uint32_t),
789 PAGE_SIZE, PAGE_NOT_CACHEABLE);
790
791 const uint32_t val = pio_read_32(ptr);
792 printf("read %" PRIxn ": %" PRIx32 "\n", argv[0].intval, val);
793
794#ifdef IO_SPACE_BOUNDARY
795 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
796 return 1;
797#endif
798
799 km_unmap((uintptr_t) ptr, sizeof(uint32_t));
800 return 1;
801}
802
803/** Write 1 byte to phys memory or io port.
804 *
805 * @param argv Argument vector.
806 *
807 * @return 0 on failure, 1 on success.
808 */
809static int cmd_pio_write_8(cmd_arg_t *argv)
810{
811 uint8_t *ptr = NULL;
812
813#ifdef IO_SPACE_BOUNDARY
814 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
815 ptr = (void *) argv[0].intval;
816 else
817#endif
818 ptr = (uint8_t *) km_map(argv[0].intval, sizeof(uint8_t),
819 PAGE_SIZE, PAGE_NOT_CACHEABLE);
820
821 printf("write %" PRIxn ": %" PRIx8 "\n", argv[0].intval,
822 (uint8_t) argv[1].intval);
823 pio_write_8(ptr, (uint8_t) argv[1].intval);
824
825#ifdef IO_SPACE_BOUNDARY
826 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
827 return 1;
828#endif
829
830 km_unmap((uintptr_t) ptr, sizeof(uint8_t));
831 return 1;
832}
833
834/** Write 2 bytes to phys memory or io port.
835 *
836 * @param argv Argument vector.
837 *
838 * @return 0 on failure, 1 on success.
839 */
840static int cmd_pio_write_16(cmd_arg_t *argv)
841{
842 uint16_t *ptr = NULL;
843
844#ifdef IO_SPACE_BOUNDARY
845 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
846 ptr = (void *) argv[0].intval;
847 else
848#endif
849 ptr = (uint16_t *) km_map(argv[0].intval, sizeof(uint16_t),
850 PAGE_SIZE, PAGE_NOT_CACHEABLE);
851
852 printf("write %" PRIxn ": %" PRIx16 "\n", argv[0].intval,
853 (uint16_t) argv[1].intval);
854 pio_write_16(ptr, (uint16_t) argv[1].intval);
855
856#ifdef IO_SPACE_BOUNDARY
857 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
858 return 1;
859#endif
860
861 km_unmap((uintptr_t) ptr, sizeof(uint16_t));
862 return 1;
863}
864
865/** Write 4 bytes to phys memory or io port.
866 *
867 * @param argv Argument vector.
868 *
869 * @return 0 on failure, 1 on success.
870 */
871static int cmd_pio_write_32(cmd_arg_t *argv)
872{
873 uint32_t *ptr = NULL;
874
875#ifdef IO_SPACE_BOUNDARY
876 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
877 ptr = (void *) argv[0].intval;
878 else
879#endif
880 ptr = (uint32_t *) km_map(argv[0].intval, sizeof(uint32_t),
881 PAGE_SIZE, PAGE_NOT_CACHEABLE);
882
883 printf("write %" PRIxn ": %" PRIx32 "\n", argv[0].intval,
884 (uint32_t) argv[1].intval);
885 pio_write_32(ptr, (uint32_t) argv[1].intval);
886
887#ifdef IO_SPACE_BOUNDARY
888 if ((void *) argv->intval < IO_SPACE_BOUNDARY)
889 return 1;
890#endif
891
892 km_unmap((uintptr_t) ptr, sizeof(uint32_t));
893 return 1;
894}
895
896/** Reboot the system.
897 *
898 * @param argv Argument vector.
899 *
900 * @return 0 on failure, 1 on success.
901 */
902int cmd_reboot(cmd_arg_t *argv)
903{
904 reboot();
905
906 /* Not reached */
907 return 1;
908}
909
910/** Print system uptime information.
911 *
912 * @param argv Argument vector.
913 *
914 * @return 0 on failure, 1 on success.
915 */
916int cmd_uptime(cmd_arg_t *argv)
917{
918 assert(uptime);
919
920 /* This doesn't have to be very accurate */
921 sysarg_t sec = uptime->seconds1;
922
923 printf("Up %" PRIun " days, %" PRIun " hours, %" PRIun " minutes, %" PRIun " seconds\n",
924 sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
925
926 return 1;
927}
928
929/** Describe specified command.
930 *
931 * @param argv Argument vector.
932 *
933 * @return 0 on failure, 1 on success.
934 */
935int cmd_desc(cmd_arg_t *argv)
936{
937 spinlock_lock(&cmd_lock);
938
939 list_foreach(cmd_list, link, cmd_info_t, hlp) {
940 spinlock_lock(&hlp->lock);
941
942 if (str_lcmp(hlp->name, (const char *) argv->buffer, str_length(hlp->name)) == 0) {
943 printf("%s - %s\n", hlp->name, hlp->description);
944 if (hlp->help)
945 hlp->help();
946 spinlock_unlock(&hlp->lock);
947 break;
948 }
949
950 spinlock_unlock(&hlp->lock);
951 }
952
953 spinlock_unlock(&cmd_lock);
954
955 return 1;
956}
957
958/** Search symbol table */
959int cmd_symaddr(cmd_arg_t *argv)
960{
961 symtab_print_search((char *) argv->buffer);
962
963 return 1;
964}
965
966/** Call function with zero parameters */
967int cmd_call0(cmd_arg_t *argv)
968{
969 uintptr_t symaddr;
970 char *symbol;
971 sysarg_t (*fnc)(void);
972 fncptr_t fptr;
973 errno_t rc;
974
975 symbol = (char *) argv->buffer;
976 rc = symtab_addr_lookup(symbol, &symaddr);
977
978 if (rc == ENOENT)
979 printf("Symbol %s not found.\n", symbol);
980 else if (rc == EOVERFLOW) {
981 symtab_print_search(symbol);
982 printf("Duplicate symbol, be more specific.\n");
983 } else if (rc == EOK) {
984 ipl_t ipl;
985
986 ipl = interrupts_disable();
987 fnc = (sysarg_t (*)(void)) arch_construct_function(&fptr,
988 (void *) symaddr, (void *) cmd_call0);
989 printf("Calling %s() (%p)\n", symbol, (void *) symaddr);
990 printf("Result: %#" PRIxn "\n", fnc());
991 interrupts_restore(ipl);
992 } else {
993 printf("No symbol information available.\n");
994 }
995 return 1;
996}
997
998/** Call function with zero parameters on each CPU */
999int cmd_mcall0(cmd_arg_t *argv)
1000{
1001 /*
1002 * For each CPU, create a thread which will
1003 * call the function.
1004 */
1005
1006 unsigned int i;
1007 for (i = 0; i < config.cpu_count; i++) {
1008 if (!cpus[i].active)
1009 continue;
1010
1011 thread_t *thread;
1012 if ((thread = thread_create((void (*)(void *)) cmd_call0,
1013 (void *) argv, TASK, THREAD_FLAG_NONE, "call0"))) {
1014 printf("cpu%u: ", i);
1015 thread_wire(thread, &cpus[i]);
1016 thread_ready(thread);
1017 thread_join(thread);
1018 thread_detach(thread);
1019 } else
1020 printf("Unable to create thread for cpu%u\n", i);
1021 }
1022
1023 return 1;
1024}
1025
1026/** Call function with one parameter */
1027int cmd_call1(cmd_arg_t *argv)
1028{
1029 uintptr_t symaddr;
1030 char *symbol;
1031 sysarg_t (*fnc)(sysarg_t, ...);
1032 sysarg_t arg1 = argv[1].intval;
1033 fncptr_t fptr;
1034 errno_t rc;
1035
1036 symbol = (char *) argv->buffer;
1037 rc = symtab_addr_lookup(symbol, &symaddr);
1038
1039 if (rc == ENOENT) {
1040 printf("Symbol %s not found.\n", symbol);
1041 } else if (rc == EOVERFLOW) {
1042 symtab_print_search(symbol);
1043 printf("Duplicate symbol, be more specific.\n");
1044 } else if (rc == EOK) {
1045 ipl_t ipl;
1046
1047 ipl = interrupts_disable();
1048 fnc = (sysarg_t (*)(sysarg_t, ...))
1049 arch_construct_function(&fptr, (void *) symaddr,
1050 (void *) cmd_call1);
1051 printf("Calling f(%#" PRIxn "): %p: %s\n", arg1,
1052 (void *) symaddr, symbol);
1053 printf("Result: %#" PRIxn "\n", fnc(arg1));
1054 interrupts_restore(ipl);
1055 } else {
1056 printf("No symbol information available.\n");
1057 }
1058
1059 return 1;
1060}
1061
1062/** Call function with two parameters */
1063int cmd_call2(cmd_arg_t *argv)
1064{
1065 uintptr_t symaddr;
1066 char *symbol;
1067 sysarg_t (*fnc)(sysarg_t, sysarg_t, ...);
1068 sysarg_t arg1 = argv[1].intval;
1069 sysarg_t arg2 = argv[2].intval;
1070 fncptr_t fptr;
1071 errno_t rc;
1072
1073 symbol = (char *) argv->buffer;
1074 rc = symtab_addr_lookup(symbol, &symaddr);
1075
1076 if (rc == ENOENT) {
1077 printf("Symbol %s not found.\n", symbol);
1078 } else if (rc == EOVERFLOW) {
1079 symtab_print_search(symbol);
1080 printf("Duplicate symbol, be more specific.\n");
1081 } else if (rc == EOK) {
1082 ipl_t ipl;
1083
1084 ipl = interrupts_disable();
1085 fnc = (sysarg_t (*)(sysarg_t, sysarg_t, ...))
1086 arch_construct_function(&fptr, (void *) symaddr,
1087 (void *) cmd_call2);
1088 printf("Calling f(%#" PRIxn ", %#" PRIxn "): %p: %s\n",
1089 arg1, arg2, (void *) symaddr, symbol);
1090 printf("Result: %#" PRIxn "\n", fnc(arg1, arg2));
1091 interrupts_restore(ipl);
1092 } else {
1093 printf("No symbol information available.\n");
1094 }
1095 return 1;
1096}
1097
1098/** Call function with three parameters */
1099int cmd_call3(cmd_arg_t *argv)
1100{
1101 uintptr_t symaddr;
1102 char *symbol;
1103 sysarg_t (*fnc)(sysarg_t, sysarg_t, sysarg_t, ...);
1104 sysarg_t arg1 = argv[1].intval;
1105 sysarg_t arg2 = argv[2].intval;
1106 sysarg_t arg3 = argv[3].intval;
1107 fncptr_t fptr;
1108 errno_t rc;
1109
1110 symbol = (char *) argv->buffer;
1111 rc = symtab_addr_lookup(symbol, &symaddr);
1112
1113 if (rc == ENOENT) {
1114 printf("Symbol %s not found.\n", symbol);
1115 } else if (rc == EOVERFLOW) {
1116 symtab_print_search(symbol);
1117 printf("Duplicate symbol, be more specific.\n");
1118 } else if (rc == EOK) {
1119 ipl_t ipl;
1120
1121 ipl = interrupts_disable();
1122 fnc = (sysarg_t (*)(sysarg_t, sysarg_t, sysarg_t, ...))
1123 arch_construct_function(&fptr, (void *) symaddr,
1124 (void *) cmd_call3);
1125 printf("Calling f(%#" PRIxn ",%#" PRIxn ", %#" PRIxn "): %p: %s\n",
1126 arg1, arg2, arg3, (void *) symaddr, symbol);
1127 printf("Result: %#" PRIxn "\n", fnc(arg1, arg2, arg3));
1128 interrupts_restore(ipl);
1129 } else {
1130 printf("No symbol information available.\n");
1131 }
1132 return 1;
1133}
1134
1135/** Print detailed description of 'describe' command. */
1136void desc_help(void)
1137{
1138 printf("Syntax: describe command_name\n");
1139}
1140
1141/** Halt the kernel.
1142 *
1143 * @param argv Argument vector (ignored).
1144 *
1145 * @return 0 on failure, 1 on success (never returns).
1146 */
1147int cmd_halt(cmd_arg_t *argv)
1148{
1149 halt();
1150 return 1;
1151}
1152
1153/** Command for printing TLB contents.
1154 *
1155 * @param argv Not used.
1156 *
1157 * @return Always returns 1.
1158 */
1159int cmd_tlb(cmd_arg_t *argv)
1160{
1161 tlb_print();
1162 return 1;
1163}
1164
1165/** Command for printing physical memory configuration.
1166 *
1167 * @param argv Not used.
1168 *
1169 * @return Always returns 1.
1170 */
1171int cmd_physmem(cmd_arg_t *argv)
1172{
1173 physmem_print();
1174 return 1;
1175}
1176
1177/** Write 4 byte value to address */
1178int cmd_set4(cmd_arg_t *argv)
1179{
1180 uintptr_t addr = 0; // Prevent -Werror=maybe-uninitialized
1181 uint32_t arg1 = argv[1].intval;
1182 bool pointer = false;
1183 errno_t rc;
1184
1185 if (((char *) argv->buffer)[0] == '*') {
1186 rc = symtab_addr_lookup((char *) argv->buffer + 1, &addr);
1187 pointer = true;
1188 } else if (((char *) argv->buffer)[0] >= '0' &&
1189 ((char *) argv->buffer)[0] <= '9') {
1190 uint64_t value;
1191 rc = str_uint64_t((char *) argv->buffer, NULL, 0, true, &value);
1192 if (rc == EOK)
1193 addr = (uintptr_t) value;
1194 } else
1195 rc = symtab_addr_lookup((char *) argv->buffer, &addr);
1196
1197 if (rc == ENOENT)
1198 printf("Symbol %s not found.\n", (char *) argv->buffer);
1199 else if (rc == EINVAL)
1200 printf("Invalid address.\n");
1201 else if (rc == EOVERFLOW) {
1202 symtab_print_search((char *) argv->buffer);
1203 printf("Duplicate symbol (be more specific) or address overflow.\n");
1204 } else if (rc == EOK) {
1205 if (pointer)
1206 addr = *(uintptr_t *) addr;
1207 printf("Writing %#" PRIx32 " -> %p\n", arg1, (void *) addr);
1208 *(uint32_t *) addr = arg1;
1209 } else
1210 printf("No symbol information available.\n");
1211
1212 return 1;
1213}
1214
1215/** Command for listing slab allocator caches
1216 *
1217 * @param argv Ignored
1218 *
1219 * @return Always 1
1220 */
1221int cmd_caches(cmd_arg_t *argv)
1222{
1223 slab_print_list();
1224 return 1;
1225}
1226
1227/** Command for dumping sysinfo
1228 *
1229 * @param argv Ignores
1230 *
1231 * @return Always 1
1232 */
1233int cmd_sysinfo(cmd_arg_t *argv)
1234{
1235 sysinfo_dump(NULL);
1236 return 1;
1237}
1238
1239/** Command for listing thread information
1240 *
1241 * @param argv Ignored
1242 *
1243 * @return Always 1
1244 */
1245int cmd_threads(cmd_arg_t *argv)
1246{
1247 if (str_cmp(flag_buf, "-a") == 0)
1248 thread_print_list(true);
1249 else if (str_cmp(flag_buf, "") == 0)
1250 thread_print_list(false);
1251 else
1252 printf("Unknown argument \"%s\".\n", flag_buf);
1253
1254 return 1;
1255}
1256
1257/** Command for listing task information
1258 *
1259 * @param argv Ignored
1260 *
1261 * @return Always 1
1262 */
1263int cmd_tasks(cmd_arg_t *argv)
1264{
1265 if (str_cmp(flag_buf, "-a") == 0)
1266 task_print_list(true);
1267 else if (str_cmp(flag_buf, "") == 0)
1268 task_print_list(false);
1269 else
1270 printf("Unknown argument \"%s\".\n", flag_buf);
1271
1272 return 1;
1273}
1274
1275#ifdef CONFIG_UDEBUG
1276
1277/** Command for printing thread stack trace
1278 *
1279 * @param argv Integer argument from cmdline expected
1280 *
1281 * return Always 1
1282 *
1283 */
1284int cmd_btrace(cmd_arg_t *argv)
1285{
1286 thread_stack_trace(argv[0].intval);
1287 return 1;
1288}
1289
1290#endif /* CONFIG_UDEBUG */
1291
1292/** Command for printing scheduler information
1293 *
1294 * @param argv Ignores
1295 *
1296 * @return Always 1
1297 */
1298int cmd_sched(cmd_arg_t *argv)
1299{
1300 sched_print_list();
1301 return 1;
1302}
1303
1304/** Prints information about the global work queue.
1305 *
1306 * @param argv Ignores
1307 *
1308 * @return Always 1
1309 */
1310int cmd_workq(cmd_arg_t *argv)
1311{
1312 workq_global_print_info();
1313 return 1;
1314}
1315
1316/** Prints RCU statistics.
1317 *
1318 * @param argv Ignores
1319 *
1320 * @return Always 1
1321 */
1322int cmd_rcu(cmd_arg_t *argv)
1323{
1324 rcu_print_stat();
1325 return 1;
1326}
1327
1328/** Command for listing memory zones
1329 *
1330 * @param argv Ignored
1331 *
1332 * return Always 1
1333 */
1334int cmd_zones(cmd_arg_t *argv)
1335{
1336 zones_print_list();
1337 return 1;
1338}
1339
1340/** Command for memory zone details
1341 *
1342 * @param argv Integer argument from cmdline expected
1343 *
1344 * return Always 1
1345 */
1346int cmd_zone(cmd_arg_t *argv)
1347{
1348 zone_print_one(argv[0].intval);
1349 return 1;
1350}
1351
1352/** Command for printing task IPC details
1353 *
1354 * @param argv Integer argument from cmdline expected
1355 *
1356 * return Always 1
1357 */
1358int cmd_ipc(cmd_arg_t *argv)
1359{
1360 ipc_print_task(argv[0].intval);
1361 return 1;
1362}
1363
1364/** Command for killing a task
1365 *
1366 * @param argv Integer argument from cmdline expected
1367 *
1368 * return 0 on failure, 1 on success.
1369 */
1370int cmd_kill(cmd_arg_t *argv)
1371{
1372 if (task_kill(argv[0].intval) != EOK)
1373 return 0;
1374
1375 return 1;
1376}
1377
1378/** Command for listing processors.
1379 *
1380 * @param argv Ignored.
1381 *
1382 * return Always 1.
1383 */
1384int cmd_cpus(cmd_arg_t *argv)
1385{
1386 cpu_list();
1387 return 1;
1388}
1389
1390/** Command for printing kernel version.
1391 *
1392 * @param argv Ignored.
1393 *
1394 * return Always 1.
1395 */
1396int cmd_version(cmd_arg_t *argv)
1397{
1398 version_print();
1399 return 1;
1400}
1401
1402/** Command for returning console back to userspace.
1403 *
1404 * @param argv Ignored.
1405 *
1406 * return Always 1.
1407 */
1408int cmd_continue(cmd_arg_t *argv)
1409{
1410 printf("The kernel will now relinquish the console.\n");
1411 release_console();
1412 indev_pop_character(stdin);
1413
1414 return 1;
1415}
1416
1417#ifdef CONFIG_TEST
1418static bool run_test(const test_t *test)
1419{
1420 printf("%s (%s)\n", test->name, test->desc);
1421
1422 /*
1423 * Update and read thread accounting
1424 * for benchmarking
1425 */
1426 irq_spinlock_lock(&TASK->lock, true);
1427 uint64_t ucycles0, kcycles0;
1428 task_get_accounting(TASK, &ucycles0, &kcycles0);
1429 irq_spinlock_unlock(&TASK->lock, true);
1430
1431 /* Execute the test */
1432 test_quiet = false;
1433 const char *ret = test->entry();
1434
1435 /* Update and read thread accounting */
1436 uint64_t ucycles1, kcycles1;
1437 irq_spinlock_lock(&TASK->lock, true);
1438 task_get_accounting(TASK, &ucycles1, &kcycles1);
1439 irq_spinlock_unlock(&TASK->lock, true);
1440
1441 uint64_t ucycles, kcycles;
1442 char usuffix, ksuffix;
1443 order_suffix(ucycles1 - ucycles0, &ucycles, &usuffix);
1444 order_suffix(kcycles1 - kcycles0, &kcycles, &ksuffix);
1445
1446 printf("Time: %" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles\n",
1447 ucycles, usuffix, kcycles, ksuffix);
1448
1449 if (ret == NULL) {
1450 printf("Test passed\n");
1451 return true;
1452 }
1453
1454 printf("%s\n", ret);
1455 return false;
1456}
1457
1458static bool run_bench(const test_t *test, const uint32_t cnt)
1459{
1460 uint32_t i;
1461 bool ret = true;
1462 uint64_t ucycles, kcycles;
1463 char usuffix, ksuffix;
1464
1465 if (cnt < 1)
1466 return true;
1467
1468 uint64_t *data = (uint64_t *) malloc(sizeof(uint64_t) * cnt);
1469 if (data == NULL) {
1470 printf("Error allocating memory for statistics\n");
1471 return false;
1472 }
1473
1474 for (i = 0; i < cnt; i++) {
1475 printf("%s (%u/%u) ... ", test->name, i + 1, cnt);
1476
1477 /*
1478 * Update and read thread accounting
1479 * for benchmarking
1480 */
1481 irq_spinlock_lock(&TASK->lock, true);
1482 uint64_t ucycles0, kcycles0;
1483 task_get_accounting(TASK, &ucycles0, &kcycles0);
1484 irq_spinlock_unlock(&TASK->lock, true);
1485
1486 /* Execute the test */
1487 test_quiet = true;
1488 const char *test_ret = test->entry();
1489
1490 /* Update and read thread accounting */
1491 irq_spinlock_lock(&TASK->lock, true);
1492 uint64_t ucycles1, kcycles1;
1493 task_get_accounting(TASK, &ucycles1, &kcycles1);
1494 irq_spinlock_unlock(&TASK->lock, true);
1495
1496 if (test_ret != NULL) {
1497 printf("%s\n", test_ret);
1498 ret = false;
1499 break;
1500 }
1501
1502 data[i] = ucycles1 - ucycles0 + kcycles1 - kcycles0;
1503 order_suffix(ucycles1 - ucycles0, &ucycles, &usuffix);
1504 order_suffix(kcycles1 - kcycles0, &kcycles, &ksuffix);
1505 printf("OK (%" PRIu64 "%c user cycles, %" PRIu64 "%c kernel cycles)\n",
1506 ucycles, usuffix, kcycles, ksuffix);
1507 }
1508
1509 if (ret) {
1510 printf("\n");
1511
1512 uint64_t sum = 0;
1513
1514 for (i = 0; i < cnt; i++) {
1515 sum += data[i];
1516 }
1517
1518 order_suffix(sum / (uint64_t) cnt, &ucycles, &usuffix);
1519 printf("Average\t\t%" PRIu64 "%c\n", ucycles, usuffix);
1520 }
1521
1522 free(data);
1523
1524 return ret;
1525}
1526
1527static void list_tests(void)
1528{
1529 size_t len = 0;
1530 test_t *test;
1531
1532 for (test = tests; test->name != NULL; test++) {
1533 if (str_length(test->name) > len)
1534 len = str_length(test->name);
1535 }
1536
1537 unsigned int _len = (unsigned int) len;
1538 if ((_len != len) || (((int) _len) < 0)) {
1539 printf("Command length overflow\n");
1540 return;
1541 }
1542
1543 for (test = tests; test->name != NULL; test++)
1544 printf("%-*s %s%s\n", _len, test->name, test->desc,
1545 (test->safe ? "" : " (unsafe)"));
1546
1547 printf("%-*s Run all safe tests\n", _len, "*");
1548}
1549
1550/** Command for listing and running kernel tests
1551 *
1552 * @param argv Argument vector.
1553 *
1554 * return Always 1.
1555 *
1556 */
1557int cmd_test(cmd_arg_t *argv)
1558{
1559 test_t *test;
1560
1561 if (str_cmp((char *) argv->buffer, "*") == 0) {
1562 for (test = tests; test->name != NULL; test++) {
1563 if (test->safe) {
1564 printf("\n");
1565 if (!run_test(test))
1566 break;
1567 }
1568 }
1569 } else if (str_cmp((char *) argv->buffer, "") != 0) {
1570 bool fnd = false;
1571
1572 for (test = tests; test->name != NULL; test++) {
1573 if (str_cmp(test->name, (char *) argv->buffer) == 0) {
1574 fnd = true;
1575 run_test(test);
1576 break;
1577 }
1578 }
1579
1580 if (!fnd)
1581 printf("Unknown test\n");
1582 } else
1583 list_tests();
1584
1585 return 1;
1586}
1587
1588/** Command for returning kernel tests as benchmarks
1589 *
1590 * @param argv Argument vector.
1591 *
1592 * return Always 1.
1593 */
1594int cmd_bench(cmd_arg_t *argv)
1595{
1596 test_t *test;
1597 uint32_t cnt = argv[1].intval;
1598
1599 if (str_cmp((char *) argv->buffer, "*") == 0) {
1600 for (test = tests; test->name != NULL; test++) {
1601 if (test->safe) {
1602 if (!run_bench(test, cnt))
1603 break;
1604 }
1605 }
1606 } else {
1607 bool fnd = false;
1608
1609 for (test = tests; test->name != NULL; test++) {
1610 if (str_cmp(test->name, (char *) argv->buffer) == 0) {
1611 fnd = true;
1612
1613 if (test->safe)
1614 run_bench(test, cnt);
1615 else
1616 printf("Unsafe test\n");
1617
1618 break;
1619 }
1620 }
1621
1622 if (!fnd)
1623 printf("Unknown test\n");
1624 }
1625
1626 return 1;
1627}
1628
1629#endif
1630
1631/** @}
1632 */
Note: See TracBrowser for help on using the repository browser.