Subversion Repositories HelenOS

Rev

Rev 4344 | Rev 4346 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2005 Jakub Jermar
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup genericconsole
  30.  * @{
  31.  */
  32.  
  33. /**
  34.  * @file    cmd.c
  35.  * @brief   Kernel console command wrappers.
  36.  *
  37.  * This file is meant to contain all wrapper functions for
  38.  * all kconsole commands. The point is in separating
  39.  * kconsole specific wrappers from kconsole-unaware functions
  40.  * from other subsystems.
  41.  */
  42.  
  43. #include <console/cmd.h>
  44. #include <console/console.h>
  45. #include <console/kconsole.h>
  46. #include <print.h>
  47. #include <panic.h>
  48. #include <arch/types.h>
  49. #include <adt/list.h>
  50. #include <arch.h>
  51. #include <config.h>
  52. #include <func.h>
  53. #include <string.h>
  54. #include <macros.h>
  55. #include <debug.h>
  56. #include <symtab.h>
  57. #include <cpu.h>
  58. #include <mm/tlb.h>
  59. #include <arch/mm/tlb.h>
  60. #include <mm/frame.h>
  61. #include <main/version.h>
  62. #include <mm/slab.h>
  63. #include <proc/scheduler.h>
  64. #include <proc/thread.h>
  65. #include <proc/task.h>
  66. #include <ipc/ipc.h>
  67. #include <ipc/irq.h>
  68.  
  69. #ifdef CONFIG_TEST
  70. #include <test.h>
  71. #endif
  72.  
  73. /* Data and methods for 'help' command. */
  74. static int cmd_help(cmd_arg_t *argv);
  75. static cmd_info_t help_info = {
  76.     .name = "help",
  77.     .description = "List of supported commands.",
  78.     .func = cmd_help,
  79.     .argc = 0
  80. };
  81.  
  82. static cmd_info_t exit_info = {
  83.     .name = "exit",
  84.     .description = "Exit kconsole.",
  85.     .argc = 0
  86. };
  87.  
  88. static int cmd_reboot(cmd_arg_t *argv);
  89. static cmd_info_t reboot_info = {
  90.     .name = "reboot",
  91.     .description = "Reboot.",
  92.     .func = cmd_reboot,
  93.     .argc = 0
  94. };
  95.  
  96. static int cmd_uptime(cmd_arg_t *argv);
  97. static cmd_info_t uptime_info = {
  98.     .name = "uptime",
  99.     .description = "Print uptime information.",
  100.     .func = cmd_uptime,
  101.     .argc = 0
  102. };
  103.  
  104. static int cmd_continue(cmd_arg_t *argv);
  105. static cmd_info_t continue_info = {
  106.     .name = "continue",
  107.     .description = "Return console back to userspace.",
  108.     .func = cmd_continue,
  109.     .argc = 0
  110. };
  111.  
  112. #ifdef CONFIG_TEST
  113. static int cmd_tests(cmd_arg_t *argv);
  114. static cmd_info_t tests_info = {
  115.     .name = "tests",
  116.     .description = "Print available kernel tests.",
  117.     .func = cmd_tests,
  118.     .argc = 0
  119. };
  120.  
  121. static char test_buf[MAX_CMDLINE + 1];
  122. static int cmd_test(cmd_arg_t *argv);
  123. static cmd_arg_t test_argv[] = {
  124.     {
  125.         .type = ARG_TYPE_STRING,
  126.         .buffer = test_buf,
  127.         .len = sizeof(test_buf)
  128.     }
  129. };
  130. static cmd_info_t test_info = {
  131.     .name = "test",
  132.     .description = "Run kernel test.",
  133.     .func = cmd_test,
  134.     .argc = 1,
  135.     .argv = test_argv
  136. };
  137.  
  138. static int cmd_bench(cmd_arg_t *argv);
  139. static cmd_arg_t bench_argv[] = {
  140.     {
  141.         .type = ARG_TYPE_STRING,
  142.         .buffer = test_buf,
  143.         .len = sizeof(test_buf)
  144.     },
  145.     {
  146.         .type = ARG_TYPE_INT,
  147.     }
  148. };
  149. static cmd_info_t bench_info = {
  150.     .name = "bench",
  151.     .description = "Run kernel test as benchmark.",
  152.     .func = cmd_bench,
  153.     .argc = 2,
  154.     .argv = bench_argv
  155. };
  156. #endif
  157.  
  158. /* Data and methods for 'description' command. */
  159. static int cmd_desc(cmd_arg_t *argv);
  160. static void desc_help(void);
  161. static char desc_buf[MAX_CMDLINE+1];
  162. static cmd_arg_t desc_argv = {
  163.     .type = ARG_TYPE_STRING,
  164.     .buffer = desc_buf,
  165.     .len = sizeof(desc_buf)
  166. };
  167. static cmd_info_t desc_info = {
  168.     .name = "describe",
  169.     .description = "Describe specified command.",
  170.     .help = desc_help,
  171.     .func = cmd_desc,
  172.     .argc = 1,
  173.     .argv = &desc_argv
  174. };
  175.  
  176. /* Data and methods for 'symaddr' command. */
  177. static int cmd_symaddr(cmd_arg_t *argv);
  178. static char symaddr_buf[MAX_CMDLINE+1];
  179. static cmd_arg_t symaddr_argv = {
  180.     .type = ARG_TYPE_STRING,
  181.     .buffer = symaddr_buf,
  182.     .len = sizeof(symaddr_buf)
  183. };
  184. static cmd_info_t symaddr_info = {
  185.     .name = "symaddr",
  186.     .description = "Return symbol address.",
  187.     .func = cmd_symaddr,
  188.     .argc = 1,
  189.     .argv = &symaddr_argv
  190. };
  191.  
  192. static char set_buf[MAX_CMDLINE+1];
  193. static int cmd_set4(cmd_arg_t *argv);
  194. static cmd_arg_t set4_argv[] = {
  195.     {
  196.         .type = ARG_TYPE_STRING,
  197.         .buffer = set_buf,
  198.         .len = sizeof(set_buf)
  199.     },
  200.     {
  201.         .type = ARG_TYPE_INT
  202.     }
  203. };
  204. static cmd_info_t set4_info = {
  205.     .name = "set4",
  206.     .description = "set <dest_addr> <value> - 4byte version",
  207.     .func = cmd_set4,
  208.     .argc = 2,
  209.     .argv = set4_argv
  210. };
  211.  
  212. /* Data and methods for 'call0' command. */
  213. static char call0_buf[MAX_CMDLINE + 1];
  214. static char carg1_buf[MAX_CMDLINE + 1];
  215. static char carg2_buf[MAX_CMDLINE + 1];
  216. static char carg3_buf[MAX_CMDLINE + 1];
  217.  
  218. static int cmd_call0(cmd_arg_t *argv);
  219. static cmd_arg_t call0_argv = {
  220.     .type = ARG_TYPE_STRING,
  221.     .buffer = call0_buf,
  222.     .len = sizeof(call0_buf)
  223. };
  224. static cmd_info_t call0_info = {
  225.     .name = "call0",
  226.     .description = "call0 <function> -> call function().",
  227.     .func = cmd_call0,
  228.     .argc = 1,
  229.     .argv = &call0_argv
  230. };
  231.  
  232. /* Data and methods for 'mcall0' command. */
  233. static int cmd_mcall0(cmd_arg_t *argv);
  234. static cmd_arg_t mcall0_argv = {
  235.     .type = ARG_TYPE_STRING,
  236.     .buffer = call0_buf,
  237.     .len = sizeof(call0_buf)
  238. };
  239. static cmd_info_t mcall0_info = {
  240.     .name = "mcall0",
  241.     .description = "mcall0 <function> -> call function() on each CPU.",
  242.     .func = cmd_mcall0,
  243.     .argc = 1,
  244.     .argv = &mcall0_argv
  245. };
  246.  
  247. /* Data and methods for 'call1' command. */
  248. static int cmd_call1(cmd_arg_t *argv);
  249. static cmd_arg_t call1_argv[] = {
  250.     {
  251.         .type = ARG_TYPE_STRING,
  252.         .buffer = call0_buf,
  253.         .len = sizeof(call0_buf)
  254.     },
  255.     {
  256.         .type = ARG_TYPE_VAR,
  257.         .buffer = carg1_buf,
  258.         .len = sizeof(carg1_buf)
  259.     }
  260. };
  261. static cmd_info_t call1_info = {
  262.     .name = "call1",
  263.     .description = "call1 <function> <arg1> -> call function(arg1).",
  264.     .func = cmd_call1,
  265.     .argc = 2,
  266.     .argv = call1_argv
  267. };
  268.  
  269. /* Data and methods for 'call2' command. */
  270. static int cmd_call2(cmd_arg_t *argv);
  271. static cmd_arg_t call2_argv[] = {
  272.     {
  273.         .type = ARG_TYPE_STRING,
  274.         .buffer = call0_buf,
  275.         .len = sizeof(call0_buf)
  276.     },
  277.     {
  278.         .type = ARG_TYPE_VAR,
  279.         .buffer = carg1_buf,
  280.         .len = sizeof(carg1_buf)
  281.     },
  282.     {
  283.         .type = ARG_TYPE_VAR,
  284.         .buffer = carg2_buf,
  285.         .len = sizeof(carg2_buf)
  286.     }
  287. };
  288. static cmd_info_t call2_info = {
  289.     .name = "call2",
  290.     .description = "call2 <function> <arg1> <arg2> -> call function(arg1,arg2).",
  291.     .func = cmd_call2,
  292.     .argc = 3,
  293.     .argv = call2_argv
  294. };
  295.  
  296. /* Data and methods for 'call3' command. */
  297. static int cmd_call3(cmd_arg_t *argv);
  298. static cmd_arg_t call3_argv[] = {
  299.     {
  300.         .type = ARG_TYPE_STRING,
  301.         .buffer = call0_buf,
  302.         .len = sizeof(call0_buf)
  303.     },
  304.     {
  305.         .type = ARG_TYPE_VAR,
  306.         .buffer = carg1_buf,
  307.         .len = sizeof(carg1_buf)
  308.     },
  309.     {
  310.         .type = ARG_TYPE_VAR,
  311.         .buffer = carg2_buf,
  312.         .len = sizeof(carg2_buf)
  313.     },
  314.     {
  315.         .type = ARG_TYPE_VAR,
  316.         .buffer = carg3_buf,
  317.         .len = sizeof(carg3_buf)
  318.     }
  319.  
  320. };
  321. static cmd_info_t call3_info = {
  322.     .name = "call3",
  323.     .description = "call3 <function> <arg1> <arg2> <arg3> -> call function(arg1,arg2,arg3).",
  324.     .func = cmd_call3,
  325.     .argc = 4,
  326.     .argv = call3_argv
  327. };
  328.  
  329. /* Data and methods for 'halt' command. */
  330. static int cmd_halt(cmd_arg_t *argv);
  331. static cmd_info_t halt_info = {
  332.     .name = "halt",
  333.     .description = "Halt the kernel.",
  334.     .func = cmd_halt,
  335.     .argc = 0
  336. };
  337.  
  338. /* Data and methods for 'physmem' command. */
  339. static int cmd_physmem(cmd_arg_t *argv);
  340. cmd_info_t physmem_info = {
  341.     .name = "physmem",
  342.     .description = "Print physical memory configuration.",
  343.     .help = NULL,
  344.     .func = cmd_physmem,
  345.     .argc = 0,
  346.     .argv = NULL
  347. };
  348.  
  349. /* Data and methods for 'tlb' command. */
  350. static int cmd_tlb(cmd_arg_t *argv);
  351. cmd_info_t tlb_info = {
  352.     .name = "tlb",
  353.     .description = "Print TLB of current processor.",
  354.     .help = NULL,
  355.     .func = cmd_tlb,
  356.     .argc = 0,
  357.     .argv = NULL
  358. };
  359.  
  360. static int cmd_threads(cmd_arg_t *argv);
  361. static cmd_info_t threads_info = {
  362.     .name = "threads",
  363.     .description = "List all threads.",
  364.     .func = cmd_threads,
  365.     .argc = 0
  366. };
  367.  
  368. static int cmd_tasks(cmd_arg_t *argv);
  369. static cmd_info_t tasks_info = {
  370.     .name = "tasks",
  371.     .description = "List all tasks.",
  372.     .func = cmd_tasks,
  373.     .argc = 0
  374. };
  375.  
  376.  
  377. static int cmd_sched(cmd_arg_t *argv);
  378. static cmd_info_t sched_info = {
  379.     .name = "scheduler",
  380.     .description = "List all scheduler information.",
  381.     .func = cmd_sched,
  382.     .argc = 0
  383. };
  384.  
  385. static int cmd_slabs(cmd_arg_t *argv);
  386. static cmd_info_t slabs_info = {
  387.     .name = "slabs",
  388.     .description = "List slab caches.",
  389.     .func = cmd_slabs,
  390.     .argc = 0
  391. };
  392.  
  393. /* Data and methods for 'zones' command */
  394. static int cmd_zones(cmd_arg_t *argv);
  395. static cmd_info_t zones_info = {
  396.     .name = "zones",
  397.     .description = "List of memory zones.",
  398.     .func = cmd_zones,
  399.     .argc = 0
  400. };
  401.  
  402. /* Data and methods for 'ipc' command */
  403. static int cmd_ipc(cmd_arg_t *argv);
  404. static cmd_arg_t ipc_argv = {
  405.     .type = ARG_TYPE_INT,
  406. };
  407. static cmd_info_t ipc_info = {
  408.     .name = "ipc",
  409.     .description = "ipc <taskid> Show IPC information of given task.",
  410.     .func = cmd_ipc,
  411.     .argc = 1,
  412.     .argv = &ipc_argv
  413. };
  414.  
  415. /* Data and methods for 'zone' command */
  416. static int cmd_zone(cmd_arg_t *argv);
  417. static cmd_arg_t zone_argv = {
  418.     .type = ARG_TYPE_INT,
  419. };
  420.  
  421. static cmd_info_t zone_info = {
  422.     .name = "zone",
  423.     .description = "Show memory zone structure.",
  424.     .func = cmd_zone,
  425.     .argc = 1,
  426.     .argv = &zone_argv
  427. };
  428.  
  429. /* Data and methods for 'cpus' command. */
  430. static int cmd_cpus(cmd_arg_t *argv);
  431. cmd_info_t cpus_info = {
  432.     .name = "cpus",
  433.     .description = "List all processors.",
  434.     .help = NULL,
  435.     .func = cmd_cpus,
  436.     .argc = 0,
  437.     .argv = NULL
  438. };
  439.  
  440. /* Data and methods for 'version' command. */
  441. static int cmd_version(cmd_arg_t *argv);
  442. cmd_info_t version_info = {
  443.     .name = "version",
  444.     .description = "Print version information.",
  445.     .help = NULL,
  446.     .func = cmd_version,
  447.     .argc = 0,
  448.     .argv = NULL
  449. };
  450.  
  451. static cmd_info_t *basic_commands[] = {
  452.     &call0_info,
  453.     &mcall0_info,
  454.     &call1_info,
  455.     &call2_info,
  456.     &call3_info,
  457.     &continue_info,
  458.     &cpus_info,
  459.     &desc_info,
  460.     &exit_info,
  461.     &reboot_info,
  462.     &uptime_info,
  463.     &halt_info,
  464.     &help_info,
  465.     &ipc_info,
  466.     &set4_info,
  467.     &slabs_info,
  468.     &symaddr_info,
  469.     &sched_info,
  470.     &threads_info,
  471.     &tasks_info,
  472.     &physmem_info,
  473.     &tlb_info,
  474.     &version_info,
  475.     &zones_info,
  476.     &zone_info,
  477. #ifdef CONFIG_TEST
  478.     &tests_info,
  479.     &test_info,
  480.     &bench_info,
  481. #endif
  482.     NULL
  483. };
  484.  
  485.  
  486. /** Initialize command info structure.
  487.  *
  488.  * @param cmd Command info structure.
  489.  *
  490.  */
  491. void cmd_initialize(cmd_info_t *cmd)
  492. {
  493.     spinlock_initialize(&cmd->lock, "cmd");
  494.     link_initialize(&cmd->link);
  495. }
  496.  
  497. /** Initialize and register commands. */
  498. void cmd_init(void)
  499. {
  500.     unsigned int i;
  501.  
  502.     for (i = 0; basic_commands[i]; i++) {
  503.         cmd_initialize(basic_commands[i]);
  504.         if (!cmd_register(basic_commands[i]))
  505.             printf("Cannot register command %s\n", basic_commands[i]->name);
  506.     }
  507. }
  508.  
  509.  
  510. /** List supported commands.
  511.  *
  512.  * @param argv Argument vector.
  513.  *
  514.  * @return 0 on failure, 1 on success.
  515.  */
  516. int cmd_help(cmd_arg_t *argv)
  517. {
  518.     spinlock_lock(&cmd_lock);
  519.    
  520.     link_t *cur;
  521.     size_t len = 0;
  522.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  523.         cmd_info_t *hlp;
  524.         hlp = list_get_instance(cur, cmd_info_t, link);
  525.        
  526.         spinlock_lock(&hlp->lock);
  527.         if (strlen(hlp->name) > len)
  528.             len = strlen(hlp->name);
  529.         spinlock_unlock(&hlp->lock);
  530.     }
  531.    
  532.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  533.         cmd_info_t *hlp;
  534.         hlp = list_get_instance(cur, cmd_info_t, link);
  535.        
  536.         spinlock_lock(&hlp->lock);
  537.         printf("%-*s %s\n", len, hlp->name, hlp->description);
  538.         spinlock_unlock(&hlp->lock);
  539.     }
  540.    
  541.     spinlock_unlock(&cmd_lock);
  542.    
  543.     return 1;
  544. }
  545.  
  546.  
  547. /** Reboot the system.
  548.  *
  549.  * @param argv Argument vector.
  550.  *
  551.  * @return 0 on failure, 1 on success.
  552.  */
  553. int cmd_reboot(cmd_arg_t *argv)
  554. {
  555.     reboot();
  556.    
  557.     /* Not reached */
  558.     return 1;
  559. }
  560.  
  561.  
  562. /** Print system uptime information.
  563.  *
  564.  * @param argv Argument vector.
  565.  *
  566.  * @return 0 on failure, 1 on success.
  567.  */
  568. int cmd_uptime(cmd_arg_t *argv)
  569. {
  570.     ASSERT(uptime);
  571.    
  572.     /* This doesn't have to be very accurate */
  573.     unative_t sec = uptime->seconds1;
  574.    
  575.     printf("Up %" PRIun " days, %" PRIun " hours, %" PRIun " minutes, %" PRIun " seconds\n",
  576.         sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
  577.    
  578.     return 1;
  579. }
  580.  
  581. /** Describe specified command.
  582.  *
  583.  * @param argv Argument vector.
  584.  *
  585.  * @return 0 on failure, 1 on success.
  586.  */
  587. int cmd_desc(cmd_arg_t *argv)
  588. {
  589.     link_t *cur;
  590.  
  591.     spinlock_lock(&cmd_lock);
  592.    
  593.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  594.         cmd_info_t *hlp;
  595.        
  596.         hlp = list_get_instance(cur, cmd_info_t, link);
  597.         spinlock_lock(&hlp->lock);
  598.  
  599.         if (strncmp(hlp->name, (const char *) argv->buffer, strlen(hlp->name)) == 0) {
  600.             printf("%s - %s\n", hlp->name, hlp->description);
  601.             if (hlp->help)
  602.                 hlp->help();
  603.             spinlock_unlock(&hlp->lock);
  604.             break;
  605.         }
  606.  
  607.         spinlock_unlock(&hlp->lock);
  608.     }
  609.    
  610.     spinlock_unlock(&cmd_lock);
  611.  
  612.     return 1;
  613. }
  614.  
  615. /** Search symbol table */
  616. int cmd_symaddr(cmd_arg_t *argv)
  617. {
  618.     symtab_print_search((char *) argv->buffer);
  619.    
  620.     return 1;
  621. }
  622.  
  623. /** Call function with zero parameters */
  624. int cmd_call0(cmd_arg_t *argv)
  625. {
  626.     uintptr_t symaddr;
  627.     char *symbol;
  628.     unative_t (*fnc)(void);
  629.     fncptr_t fptr;
  630.    
  631.     symaddr = get_symbol_addr((char *) argv->buffer);
  632.     if (!symaddr)
  633.         printf("Symbol %s not found.\n", argv->buffer);
  634.     else if (symaddr == (uintptr_t) -1) {
  635.         symtab_print_search((char *) argv->buffer);
  636.         printf("Duplicate symbol, be more specific.\n");
  637.     } else {
  638.         symbol = get_symtab_entry(symaddr);
  639.         fnc = (unative_t (*)(void)) arch_construct_function(&fptr, (void *) symaddr, (void *) cmd_call0);
  640.         printf("Calling %s() (%p)\n", symbol, symaddr);
  641.         printf("Result: %#" PRIxn "\n", fnc());
  642.     }
  643.    
  644.     return 1;
  645. }
  646.  
  647. /** Call function with zero parameters on each CPU */
  648. int cmd_mcall0(cmd_arg_t *argv)
  649. {
  650.     /*
  651.      * For each CPU, create a thread which will
  652.      * call the function.
  653.      */
  654.    
  655.     count_t i;
  656.     for (i = 0; i < config.cpu_count; i++) {
  657.         if (!cpus[i].active)
  658.             continue;
  659.        
  660.         thread_t *t;
  661.         if ((t = thread_create((void (*)(void *)) cmd_call0, (void *) argv, TASK, THREAD_FLAG_WIRED, "call0", false))) {
  662.             spinlock_lock(&t->lock);
  663.             t->cpu = &cpus[i];
  664.             spinlock_unlock(&t->lock);
  665.             printf("cpu%u: ", i);
  666.             thread_ready(t);
  667.             thread_join(t);
  668.             thread_detach(t);
  669.         } else
  670.             printf("Unable to create thread for cpu%u\n", i);
  671.     }
  672.    
  673.     return 1;
  674. }
  675.  
  676. /** Call function with one parameter */
  677. int cmd_call1(cmd_arg_t *argv)
  678. {
  679.     uintptr_t symaddr;
  680.     char *symbol;
  681.     unative_t (*fnc)(unative_t, ...);
  682.     unative_t arg1 = argv[1].intval;
  683.     fncptr_t fptr;
  684.    
  685.     symaddr = get_symbol_addr((char *) argv->buffer);
  686.     if (!symaddr)
  687.         printf("Symbol %s not found.\n", argv->buffer);
  688.     else if (symaddr == (uintptr_t) -1) {
  689.         symtab_print_search((char *) argv->buffer);
  690.         printf("Duplicate symbol, be more specific.\n");
  691.     } else {
  692.         symbol = get_symtab_entry(symaddr);
  693.         fnc = (unative_t (*)(unative_t, ...)) arch_construct_function(&fptr, (void *) symaddr, (void *) cmd_call1);
  694.         printf("Calling f(%#" PRIxn "): %p: %s\n", arg1, symaddr, symbol);
  695.         printf("Result: %#" PRIxn "\n", fnc(arg1));
  696.     }
  697.    
  698.     return 1;
  699. }
  700.  
  701. /** Call function with two parameters */
  702. int cmd_call2(cmd_arg_t *argv)
  703. {
  704.     uintptr_t symaddr;
  705.     char *symbol;
  706.     unative_t (*fnc)(unative_t, unative_t, ...);
  707.     unative_t arg1 = argv[1].intval;
  708.     unative_t arg2 = argv[2].intval;
  709.     fncptr_t fptr;
  710.    
  711.     symaddr = get_symbol_addr((char *) argv->buffer);
  712.     if (!symaddr)
  713.         printf("Symbol %s not found.\n", argv->buffer);
  714.     else if (symaddr == (uintptr_t) -1) {
  715.         symtab_print_search((char *) argv->buffer);
  716.         printf("Duplicate symbol, be more specific.\n");
  717.     } else {
  718.         symbol = get_symtab_entry(symaddr);
  719.         fnc = (unative_t (*)(unative_t, unative_t, ...)) arch_construct_function(&fptr, (void *) symaddr, (void *) cmd_call2);
  720.         printf("Calling f(%#" PRIxn ", %#" PRIxn "): %p: %s\n",
  721.                arg1, arg2, symaddr, symbol);
  722.         printf("Result: %#" PRIxn "\n", fnc(arg1, arg2));
  723.     }
  724.    
  725.     return 1;
  726. }
  727.  
  728. /** Call function with three parameters */
  729. int cmd_call3(cmd_arg_t *argv)
  730. {
  731.     uintptr_t symaddr;
  732.     char *symbol;
  733.     unative_t (*fnc)(unative_t, unative_t, unative_t, ...);
  734.     unative_t arg1 = argv[1].intval;
  735.     unative_t arg2 = argv[2].intval;
  736.     unative_t arg3 = argv[3].intval;
  737.     fncptr_t fptr;
  738.    
  739.     symaddr = get_symbol_addr((char *) argv->buffer);
  740.     if (!symaddr)
  741.         printf("Symbol %s not found.\n", argv->buffer);
  742.     else if (symaddr == (uintptr_t) -1) {
  743.         symtab_print_search((char *) argv->buffer);
  744.         printf("Duplicate symbol, be more specific.\n");
  745.     } else {
  746.         symbol = get_symtab_entry(symaddr);
  747.         fnc = (unative_t (*)(unative_t, unative_t, unative_t, ...)) arch_construct_function(&fptr, (void *) symaddr, (void *) cmd_call3);
  748.         printf("Calling f(%#" PRIxn ",%#" PRIxn ", %#" PRIxn "): %p: %s\n",
  749.                arg1, arg2, arg3, symaddr, symbol);
  750.         printf("Result: %#" PRIxn "\n", fnc(arg1, arg2, arg3));
  751.     }
  752.    
  753.     return 1;
  754. }
  755.  
  756.  
  757. /** Print detailed description of 'describe' command. */
  758. void desc_help(void)
  759. {
  760.     printf("Syntax: describe command_name\n");
  761. }
  762.  
  763. /** Halt the kernel.
  764.  *
  765.  * @param argv Argument vector (ignored).
  766.  *
  767.  * @return 0 on failure, 1 on success (never returns).
  768.  */
  769. int cmd_halt(cmd_arg_t *argv)
  770. {
  771.     halt();
  772.     return 1;
  773. }
  774.  
  775. /** Command for printing TLB contents.
  776.  *
  777.  * @param argv Not used.
  778.  *
  779.  * @return Always returns 1.
  780.  */
  781. int cmd_tlb(cmd_arg_t *argv)
  782. {
  783.     tlb_print();
  784.     return 1;
  785. }
  786.  
  787. /** Command for printing physical memory configuration.
  788.  *
  789.  * @param argv Not used.
  790.  *
  791.  * @return Always returns 1.
  792.  */
  793. int cmd_physmem(cmd_arg_t *argv)
  794. {
  795.     physmem_print();
  796.     return 1;
  797. }
  798.  
  799. /** Write 4 byte value to address */
  800. int cmd_set4(cmd_arg_t *argv)
  801. {
  802.     uint32_t *addr;
  803.     uint32_t arg1 = argv[1].intval;
  804.     bool pointer = false;
  805.  
  806.     if (((char *)argv->buffer)[0] == '*') {
  807.         addr = (uint32_t *) get_symbol_addr((char *) argv->buffer + 1);
  808.         pointer = true;
  809.     } else if (((char *) argv->buffer)[0] >= '0' &&
  810.            ((char *)argv->buffer)[0] <= '9')
  811.         addr = (uint32_t *)atoi((char *)argv->buffer);
  812.     else
  813.         addr = (uint32_t *)get_symbol_addr((char *) argv->buffer);
  814.  
  815.     if (!addr)
  816.         printf("Symbol %s not found.\n", argv->buffer);
  817.     else if (addr == (uint32_t *) -1) {
  818.         symtab_print_search((char *) argv->buffer);
  819.         printf("Duplicate symbol, be more specific.\n");
  820.     } else {
  821.         if (pointer)
  822.             addr = (uint32_t *)(*(unative_t *)addr);
  823.         printf("Writing %#" PRIx64 " -> %p\n", arg1, addr);
  824.         *addr = arg1;
  825.        
  826.     }
  827.    
  828.     return 1;
  829. }
  830.  
  831. /** Command for listings SLAB caches
  832.  *
  833.  * @param argv Ignores
  834.  *
  835.  * @return Always 1
  836.  */
  837. int cmd_slabs(cmd_arg_t * argv) {
  838.     slab_print_list();
  839.     return 1;
  840. }
  841.  
  842.  
  843. /** Command for listings Thread information
  844.  *
  845.  * @param argv Ignores
  846.  *
  847.  * @return Always 1
  848.  */
  849. int cmd_threads(cmd_arg_t * argv) {
  850.     thread_print_list();
  851.     return 1;
  852. }
  853.  
  854. /** Command for listings Task information
  855.  *
  856.  * @param argv Ignores
  857.  *
  858.  * @return Always 1
  859.  */
  860. int cmd_tasks(cmd_arg_t * argv) {
  861.     task_print_list();
  862.     return 1;
  863. }
  864.  
  865. /** Command for listings Thread information
  866.  *
  867.  * @param argv Ignores
  868.  *
  869.  * @return Always 1
  870.  */
  871. int cmd_sched(cmd_arg_t * argv) {
  872.     sched_print_list();
  873.     return 1;
  874. }
  875.  
  876. /** Command for listing memory zones
  877.  *
  878.  * @param argv Ignored
  879.  *
  880.  * return Always 1
  881.  */
  882. int cmd_zones(cmd_arg_t * argv) {
  883.     zone_print_list();
  884.     return 1;
  885. }
  886.  
  887. /** Command for memory zone details
  888.  *
  889.  * @param argv Integer argument from cmdline expected
  890.  *
  891.  * return Always 1
  892.  */
  893. int cmd_zone(cmd_arg_t * argv) {
  894.     zone_print_one(argv[0].intval);
  895.     return 1;
  896. }
  897.  
  898. /** Command for printing task ipc details
  899.  *
  900.  * @param argv Integer argument from cmdline expected
  901.  *
  902.  * return Always 1
  903.  */
  904. int cmd_ipc(cmd_arg_t * argv) {
  905.     ipc_print_task(argv[0].intval);
  906.     return 1;
  907. }
  908.  
  909.  
  910. /** Command for listing processors.
  911.  *
  912.  * @param argv Ignored.
  913.  *
  914.  * return Always 1.
  915.  */
  916. int cmd_cpus(cmd_arg_t *argv)
  917. {
  918.     cpu_list();
  919.     return 1;
  920. }
  921.  
  922. /** Command for printing kernel version.
  923.  *
  924.  * @param argv Ignored.
  925.  *
  926.  * return Always 1.
  927.  */
  928. int cmd_version(cmd_arg_t *argv)
  929. {
  930.     version_print();
  931.     return 1;
  932. }
  933.  
  934. /** Command for returning console back to userspace.
  935.  *
  936.  * @param argv Ignored.
  937.  *
  938.  * return Always 1.
  939.  */
  940. int cmd_continue(cmd_arg_t *argv)
  941. {
  942.     printf("The kernel will now relinquish the console.\n");
  943.     release_console();
  944.    
  945.     if ((kconsole_notify) && (kconsole_irq.notif_cfg.notify))
  946.         ipc_irq_send_msg_0(&kconsole_irq);
  947.    
  948.     return 1;
  949. }
  950.  
  951. #ifdef CONFIG_TEST
  952. /** Command for printing kernel tests list.
  953.  *
  954.  * @param argv Ignored.
  955.  *
  956.  * return Always 1.
  957.  */
  958. int cmd_tests(cmd_arg_t *argv)
  959. {
  960.     size_t len = 0;
  961.     test_t *test;
  962.     for (test = tests; test->name != NULL; test++) {
  963.         if (strlen(test->name) > len)
  964.             len = strlen(test->name);
  965.     }
  966.    
  967.     for (test = tests; test->name != NULL; test++)
  968.         printf("%-*s %s%s\n", len, test->name, test->desc, (test->safe ? "" : " (unsafe)"));
  969.    
  970.     printf("%-*s Run all safe tests\n", len, "*");
  971.     return 1;
  972. }
  973.  
  974. static bool run_test(const test_t *test)
  975. {
  976.     printf("%s (%s)\n", test->name, test->desc);
  977.    
  978.     /* Update and read thread accounting
  979.        for benchmarking */
  980.     ipl_t ipl = interrupts_disable();
  981.     spinlock_lock(&TASK->lock);
  982.     uint64_t t0 = task_get_accounting(TASK);
  983.     spinlock_unlock(&TASK->lock);
  984.     interrupts_restore(ipl);
  985.    
  986.     /* Execute the test */
  987.     char * ret = test->entry(false);
  988.    
  989.     /* Update and read thread accounting */
  990.     ipl = interrupts_disable();
  991.     spinlock_lock(&TASK->lock);
  992.     uint64_t dt = task_get_accounting(TASK) - t0;
  993.     spinlock_unlock(&TASK->lock);
  994.     interrupts_restore(ipl);
  995.    
  996.     uint64_t cycles;
  997.     char suffix;
  998.     order(dt, &cycles, &suffix);
  999.        
  1000.     printf("Time: %" PRIu64 "%c cycles\n", cycles, suffix);
  1001.    
  1002.     if (ret == NULL) {
  1003.         printf("Test passed\n");
  1004.         return true;
  1005.     }
  1006.  
  1007.     printf("%s\n", ret);
  1008.     return false;
  1009. }
  1010.  
  1011. static bool run_bench(const test_t *test, const uint32_t cnt)
  1012. {
  1013.     uint32_t i;
  1014.     bool ret = true;
  1015.     uint64_t cycles;
  1016.     char suffix;
  1017.    
  1018.     if (cnt < 1)
  1019.         return true;
  1020.    
  1021.     uint64_t *data = (uint64_t *) malloc(sizeof(uint64_t) * cnt, 0);
  1022.     if (data == NULL) {
  1023.         printf("Error allocating memory for statistics\n");
  1024.         return false;
  1025.     }
  1026.    
  1027.     for (i = 0; i < cnt; i++) {
  1028.         printf("%s (%u/%u) ... ", test->name, i + 1, cnt);
  1029.        
  1030.         /* Update and read thread accounting
  1031.            for benchmarking */
  1032.         ipl_t ipl = interrupts_disable();
  1033.         spinlock_lock(&TASK->lock);
  1034.         uint64_t t0 = task_get_accounting(TASK);
  1035.         spinlock_unlock(&TASK->lock);
  1036.         interrupts_restore(ipl);
  1037.        
  1038.         /* Execute the test */
  1039.         char * ret = test->entry(true);
  1040.        
  1041.         /* Update and read thread accounting */
  1042.         ipl = interrupts_disable();
  1043.         spinlock_lock(&TASK->lock);
  1044.         uint64_t dt = task_get_accounting(TASK) - t0;
  1045.         spinlock_unlock(&TASK->lock);
  1046.         interrupts_restore(ipl);
  1047.        
  1048.         if (ret != NULL) {
  1049.             printf("%s\n", ret);
  1050.             ret = false;
  1051.             break;
  1052.         }
  1053.        
  1054.         data[i] = dt;
  1055.         order(dt, &cycles, &suffix);
  1056.         printf("OK (%" PRIu64 "%c cycles)\n", cycles, suffix);
  1057.     }
  1058.    
  1059.     if (ret) {
  1060.         printf("\n");
  1061.        
  1062.         uint64_t sum = 0;
  1063.        
  1064.         for (i = 0; i < cnt; i++) {
  1065.             sum += data[i];
  1066.         }
  1067.        
  1068.         order(sum / (uint64_t) cnt, &cycles, &suffix);
  1069.         printf("Average\t\t%" PRIu64 "%c\n", cycles, suffix);
  1070.     }
  1071.    
  1072.     free(data);
  1073.    
  1074.     return ret;
  1075. }
  1076.  
  1077. /** Command for returning kernel tests
  1078.  *
  1079.  * @param argv Argument vector.
  1080.  *
  1081.  * return Always 1.
  1082.  */
  1083. int cmd_test(cmd_arg_t *argv)
  1084. {
  1085.     test_t *test;
  1086.    
  1087.     if (strcmp((char *) argv->buffer, "*") == 0) {
  1088.         for (test = tests; test->name != NULL; test++) {
  1089.             if (test->safe) {
  1090.                 printf("\n");
  1091.                 if (!run_test(test))
  1092.                     break;
  1093.             }
  1094.         }
  1095.     } else {
  1096.         bool fnd = false;
  1097.        
  1098.         for (test = tests; test->name != NULL; test++) {
  1099.             if (strcmp(test->name, (char *) argv->buffer) == 0) {
  1100.                 fnd = true;
  1101.                 run_test(test);
  1102.                 break;
  1103.             }
  1104.         }
  1105.        
  1106.         if (!fnd)
  1107.             printf("Unknown test\n");
  1108.     }
  1109.    
  1110.     return 1;
  1111. }
  1112.  
  1113. /** Command for returning kernel tests as benchmarks
  1114.  *
  1115.  * @param argv Argument vector.
  1116.  *
  1117.  * return Always 1.
  1118.  */
  1119. int cmd_bench(cmd_arg_t *argv)
  1120. {
  1121.     test_t *test;
  1122.     uint32_t cnt = argv[1].intval;
  1123.    
  1124.     bool fnd = false;
  1125.    
  1126.     for (test = tests; test->name != NULL; test++) {
  1127.         if (strcmp(test->name, (char *) argv->buffer) == 0) {
  1128.             fnd = true;
  1129.            
  1130.             if (test->safe)
  1131.                 run_bench(test, cnt);
  1132.             else
  1133.                 printf("Unsafe test\n");
  1134.            
  1135.             break;
  1136.         }
  1137.     }
  1138.        
  1139.     if (!fnd)
  1140.         printf("Unknown test\n");
  1141.  
  1142.     return 1;
  1143. }
  1144.  
  1145. #endif
  1146.  
  1147. /** @}
  1148.  */
  1149.