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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 973be387 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • 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 <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
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 errno_t 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 errno_t 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 errno_t 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 errno_t 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 errno_t 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 listing slab allocator caches
1217 *
1218 * @param argv Ignored
1219 *
1220 * @return Always 1
1221 */
1222int cmd_caches(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.