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

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

Declare malloc() etc in standard <stdlib.h> rather than <mm/slab.h>

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