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

Last change on this file since 690ad20 was f35749e, checked in by Jiri Svoboda <jiri@…>, 4 months ago

System restart via shutdown -r

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