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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a363016 was a363016, checked in by Aurelio Colosimo <aurelio@…>, 9 years ago

kconsole tab completion: call* argument hints restored by using proper callback

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