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

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

Merge from lp:~adam-hraska+lp/helenos/rcu/.

Only merge from the feature branch and resolve all conflicts.

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