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

Last change on this file since a064d4f was a064d4f, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 18 months ago

Make thread_join() imply thread_put()

This makes the function more similar to traditional threading APIs.

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