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

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

System restart via shutdown -r

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