Subversion Repositories HelenOS

Rev

Rev 1264 | Rev 1573 | 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. /**
  30.  * @file    cmd.c
  31.  * @brief   Kernel console command wrappers.
  32.  *
  33.  * This file is meant to contain all wrapper functions for
  34.  * all kconsole commands. The point is in separating
  35.  * kconsole specific wrappers from kconsole-unaware functions
  36.  * from other subsystems.
  37.  */
  38.  
  39. #include <console/cmd.h>
  40. #include <console/console.h>
  41. #include <console/kconsole.h>
  42. #include <print.h>
  43. #include <panic.h>
  44. #include <typedefs.h>
  45. #include <arch/types.h>
  46. #include <adt/list.h>
  47. #include <arch.h>
  48. #include <func.h>
  49. #include <macros.h>
  50. #include <debug.h>
  51. #include <symtab.h>
  52. #include <cpu.h>
  53. #include <mm/tlb.h>
  54. #include <arch/mm/tlb.h>
  55. #include <mm/frame.h>
  56. #include <main/version.h>
  57. #include <mm/slab.h>
  58. #include <proc/scheduler.h>
  59. #include <proc/thread.h>
  60. #include <proc/task.h>
  61.  
  62. /** Data and methods for 'help' command. */
  63. static int cmd_help(cmd_arg_t *argv);
  64. static cmd_info_t help_info = {
  65.     .name = "help",
  66.     .description = "List of supported commands.",
  67.     .func = cmd_help,
  68.     .argc = 0
  69. };
  70.  
  71. static cmd_info_t exit_info = {
  72.     .name = "exit",
  73.     .description ="Exit kconsole",
  74.     .argc = 0
  75. };
  76.  
  77. static int cmd_continue(cmd_arg_t *argv);
  78. static cmd_info_t continue_info = {
  79.     .name = "continue",
  80.     .description ="Return console back to userspace",
  81.     .func = cmd_continue,
  82.     .argc = 0
  83. };
  84.  
  85. /** Data and methods for 'description' command. */
  86. static int cmd_desc(cmd_arg_t *argv);
  87. static void desc_help(void);
  88. static char desc_buf[MAX_CMDLINE+1];
  89. static cmd_arg_t desc_argv = {
  90.     .type = ARG_TYPE_STRING,
  91.     .buffer = desc_buf,
  92.     .len = sizeof(desc_buf)
  93. };
  94. static cmd_info_t desc_info = {
  95.     .name = "describe",
  96.     .description = "Describe specified command.",
  97.     .help = desc_help,
  98.     .func = cmd_desc,
  99.     .argc = 1,
  100.     .argv = &desc_argv
  101. };
  102.  
  103. /** Data and methods for 'symaddr' command. */
  104. static int cmd_symaddr(cmd_arg_t *argv);
  105. static char symaddr_buf[MAX_CMDLINE+1];
  106. static cmd_arg_t symaddr_argv = {
  107.     .type = ARG_TYPE_STRING,
  108.     .buffer = symaddr_buf,
  109.     .len = sizeof(symaddr_buf)
  110. };
  111. static cmd_info_t symaddr_info = {
  112.     .name = "symaddr",
  113.     .description = "Return symbol address.",
  114.     .func = cmd_symaddr,
  115.     .argc = 1,
  116.     .argv = &symaddr_argv
  117. };
  118.  
  119. static char set_buf[MAX_CMDLINE+1];
  120. static int cmd_set4(cmd_arg_t *argv);
  121. static cmd_arg_t set4_argv[] = {
  122.     {
  123.         .type = ARG_TYPE_STRING,
  124.         .buffer = set_buf,
  125.         .len = sizeof(set_buf)
  126.     },
  127.     {
  128.         .type = ARG_TYPE_INT
  129.     }
  130. };
  131. static cmd_info_t set4_info = {
  132.     .name = "set4",
  133.     .description = "set <dest_addr> <value> - 4byte version",
  134.     .func = cmd_set4,
  135.     .argc = 2,
  136.     .argv = set4_argv
  137. };
  138.  
  139. /** Data and methods for 'call0' command. */
  140. static char call0_buf[MAX_CMDLINE+1];
  141. static char carg1_buf[MAX_CMDLINE+1];
  142. static char carg2_buf[MAX_CMDLINE+1];
  143. static char carg3_buf[MAX_CMDLINE+1];
  144.  
  145. static int cmd_call0(cmd_arg_t *argv);
  146. static cmd_arg_t call0_argv = {
  147.     .type = ARG_TYPE_STRING,
  148.     .buffer = call0_buf,
  149.     .len = sizeof(call0_buf)
  150. };
  151. static cmd_info_t call0_info = {
  152.     .name = "call0",
  153.     .description = "call0 <function> -> call function().",
  154.     .func = cmd_call0,
  155.     .argc = 1,
  156.     .argv = &call0_argv
  157. };
  158.  
  159. /** Data and methods for 'call1' command. */
  160. static int cmd_call1(cmd_arg_t *argv);
  161. static cmd_arg_t call1_argv[] = {
  162.     {
  163.         .type = ARG_TYPE_STRING,
  164.         .buffer = call0_buf,
  165.         .len = sizeof(call0_buf)
  166.     },
  167.     {
  168.         .type = ARG_TYPE_VAR,
  169.         .buffer = carg1_buf,
  170.         .len = sizeof(carg1_buf)
  171.     }
  172. };
  173. static cmd_info_t call1_info = {
  174.     .name = "call1",
  175.     .description = "call1 <function> <arg1> -> call function(arg1).",
  176.     .func = cmd_call1,
  177.     .argc = 2,
  178.     .argv = call1_argv
  179. };
  180.  
  181. /** Data and methods for 'call2' command. */
  182. static int cmd_call2(cmd_arg_t *argv);
  183. static cmd_arg_t call2_argv[] = {
  184.     {
  185.         .type = ARG_TYPE_STRING,
  186.         .buffer = call0_buf,
  187.         .len = sizeof(call0_buf)
  188.     },
  189.     {
  190.         .type = ARG_TYPE_VAR,
  191.         .buffer = carg1_buf,
  192.         .len = sizeof(carg1_buf)
  193.     },
  194.     {
  195.         .type = ARG_TYPE_VAR,
  196.         .buffer = carg2_buf,
  197.         .len = sizeof(carg2_buf)
  198.     }
  199. };
  200. static cmd_info_t call2_info = {
  201.     .name = "call2",
  202.     .description = "call2 <function> <arg1> <arg2> -> call function(arg1,arg2).",
  203.     .func = cmd_call2,
  204.     .argc = 3,
  205.     .argv = call2_argv
  206. };
  207.  
  208. /** Data and methods for 'call3' command. */
  209. static int cmd_call3(cmd_arg_t *argv);
  210. static cmd_arg_t call3_argv[] = {
  211.     {
  212.         .type = ARG_TYPE_STRING,
  213.         .buffer = call0_buf,
  214.         .len = sizeof(call0_buf)
  215.     },
  216.     {
  217.         .type = ARG_TYPE_VAR,
  218.         .buffer = carg1_buf,
  219.         .len = sizeof(carg1_buf)
  220.     },
  221.     {
  222.         .type = ARG_TYPE_VAR,
  223.         .buffer = carg2_buf,
  224.         .len = sizeof(carg2_buf)
  225.     },
  226.     {
  227.         .type = ARG_TYPE_VAR,
  228.         .buffer = carg3_buf,
  229.         .len = sizeof(carg3_buf)
  230.     }
  231.  
  232. };
  233. static cmd_info_t call3_info = {
  234.     .name = "call3",
  235.     .description = "call3 <function> <arg1> <arg2> <arg3> -> call function(arg1,arg2,arg3).",
  236.     .func = cmd_call3,
  237.     .argc = 4,
  238.     .argv = call3_argv
  239. };
  240.  
  241. /** Data and methods for 'halt' command. */
  242. static int cmd_halt(cmd_arg_t *argv);
  243. static cmd_info_t halt_info = {
  244.     .name = "halt",
  245.     .description = "Halt the kernel.",
  246.     .func = cmd_halt,
  247.     .argc = 0
  248. };
  249.  
  250. /** Data and methods for 'tlb' command. */
  251. static int cmd_tlb(cmd_arg_t *argv);
  252. cmd_info_t tlb_info = {
  253.     .name = "tlb",
  254.     .description = "Print TLB of current processor.",
  255.     .help = NULL,
  256.     .func = cmd_tlb,
  257.     .argc = 0,
  258.     .argv = NULL
  259. };
  260.  
  261. static int cmd_threads(cmd_arg_t *argv);
  262. static cmd_info_t threads_info = {
  263.     .name = "threads",
  264.     .description = "List all threads",
  265.     .func = cmd_threads,
  266.     .argc = 0
  267. };
  268.  
  269. static int cmd_tasks(cmd_arg_t *argv);
  270. static cmd_info_t tasks_info = {
  271.     .name = "tasks",
  272.     .description = "List all tasks",
  273.     .func = cmd_tasks,
  274.     .argc = 0
  275. };
  276.  
  277.  
  278. static int cmd_sched(cmd_arg_t *argv);
  279. static cmd_info_t sched_info = {
  280.     .name = "scheduler",
  281.     .description = "List all scheduler information",
  282.     .func = cmd_sched,
  283.     .argc = 0
  284. };
  285.  
  286. static int cmd_slabs(cmd_arg_t *argv);
  287. static cmd_info_t slabs_info = {
  288.     .name = "slabs",
  289.     .description = "List SLAB caches.",
  290.     .func = cmd_slabs,
  291.     .argc = 0
  292. };
  293.  
  294. /** Data and methods for 'zones' command */
  295. static int cmd_zones(cmd_arg_t *argv);
  296. static cmd_info_t zones_info = {
  297.     .name = "zones",
  298.     .description = "List of memory zones.",
  299.     .func = cmd_zones,
  300.     .argc = 0
  301. };
  302.  
  303. /** Data and methods for 'zone' command */
  304. static int cmd_zone(cmd_arg_t *argv);
  305. static cmd_arg_t zone_argv = {
  306.     .type = ARG_TYPE_INT,
  307. };
  308.  
  309. static cmd_info_t zone_info = {
  310.     .name = "zone",
  311.     .description = "Show memory zone structure.",
  312.     .func = cmd_zone,
  313.     .argc = 1,
  314.     .argv = &zone_argv
  315. };
  316.  
  317. /** Data and methods for 'cpus' command. */
  318. static int cmd_cpus(cmd_arg_t *argv);
  319. cmd_info_t cpus_info = {
  320.     .name = "cpus",
  321.     .description = "List all processors.",
  322.     .help = NULL,
  323.     .func = cmd_cpus,
  324.     .argc = 0,
  325.     .argv = NULL
  326. };
  327.  
  328. /** Data and methods for 'version' command. */
  329. static int cmd_version(cmd_arg_t *argv);
  330. cmd_info_t version_info = {
  331.     .name = "version",
  332.     .description = "Print version information.",
  333.     .help = NULL,
  334.     .func = cmd_version,
  335.     .argc = 0,
  336.     .argv = NULL
  337. };
  338.  
  339. static cmd_info_t *basic_commands[] = {
  340.     &call0_info,
  341.     &call1_info,
  342.     &call2_info,
  343.     &call3_info,
  344.     &continue_info,
  345.     &cpus_info,
  346.     &desc_info,
  347.     &exit_info,
  348.     &halt_info,
  349.     &help_info,
  350.     &set4_info,
  351.     &slabs_info,
  352.     &symaddr_info,
  353.     &sched_info,
  354.     &threads_info,
  355.     &tasks_info,
  356.     &tlb_info,
  357.     &version_info,
  358.     &zones_info,
  359.     &zone_info,
  360.     NULL
  361. };
  362.  
  363.  
  364. /** Initialize command info structure.
  365.  *
  366.  * @param cmd Command info structure.
  367.  *
  368.  */
  369. void cmd_initialize(cmd_info_t *cmd)
  370. {
  371.     spinlock_initialize(&cmd->lock, "cmd");
  372.     link_initialize(&cmd->link);
  373. }
  374.  
  375. /** Initialize and register commands. */
  376. void cmd_init(void)
  377. {
  378.     int i;
  379.  
  380.     for (i=0;basic_commands[i]; i++) {
  381.         cmd_initialize(basic_commands[i]);
  382.         if (!cmd_register(basic_commands[i]))
  383.             panic("could not register command %s\n",
  384.                   basic_commands[i]->name);
  385.     }
  386. }
  387.  
  388.  
  389. /** List supported commands.
  390.  *
  391.  * @param argv Argument vector.
  392.  *
  393.  * @return 0 on failure, 1 on success.
  394.  */
  395. int cmd_help(cmd_arg_t *argv)
  396. {
  397.     link_t *cur;
  398.  
  399.     spinlock_lock(&cmd_lock);
  400.    
  401.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  402.         cmd_info_t *hlp;
  403.        
  404.         hlp = list_get_instance(cur, cmd_info_t, link);
  405.         spinlock_lock(&hlp->lock);
  406.        
  407.         printf("%s - %s\n", hlp->name, hlp->description);
  408.  
  409.         spinlock_unlock(&hlp->lock);
  410.     }
  411.    
  412.     spinlock_unlock(&cmd_lock);
  413.  
  414.     return 1;
  415. }
  416.  
  417. /** Describe specified command.
  418.  *
  419.  * @param argv Argument vector.
  420.  *
  421.  * @return 0 on failure, 1 on success.
  422.  */
  423. int cmd_desc(cmd_arg_t *argv)
  424. {
  425.     link_t *cur;
  426.  
  427.     spinlock_lock(&cmd_lock);
  428.    
  429.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  430.         cmd_info_t *hlp;
  431.        
  432.         hlp = list_get_instance(cur, cmd_info_t, link);
  433.         spinlock_lock(&hlp->lock);
  434.  
  435.         if (strncmp(hlp->name, (const char *) argv->buffer, strlen(hlp->name)) == 0) {
  436.             printf("%s - %s\n", hlp->name, hlp->description);
  437.             if (hlp->help)
  438.                 hlp->help();
  439.             spinlock_unlock(&hlp->lock);
  440.             break;
  441.         }
  442.  
  443.         spinlock_unlock(&hlp->lock);
  444.     }
  445.    
  446.     spinlock_unlock(&cmd_lock);
  447.  
  448.     return 1;
  449. }
  450.  
  451. /** Search symbol table */
  452. int cmd_symaddr(cmd_arg_t *argv)
  453. {
  454.     symtab_print_search(argv->buffer);
  455.    
  456.     return 1;
  457. }
  458.  
  459. /** Call function with zero parameters */
  460. int cmd_call0(cmd_arg_t *argv)
  461. {
  462.     __address symaddr;
  463.     char *symbol;
  464.     __native (*f)(void);
  465.  
  466.     symaddr = get_symbol_addr(argv->buffer);
  467.     if (!symaddr)
  468.         printf("Symbol %s not found.\n", argv->buffer);
  469.     else if (symaddr == (__address) -1) {
  470.         symtab_print_search(argv->buffer);
  471.         printf("Duplicate symbol, be more specific.\n");
  472.     } else {
  473.         symbol = get_symtab_entry(symaddr);
  474.         printf("Calling f(): %.*p: %s\n", sizeof(__address) * 2, symaddr, symbol);
  475.         f =  (__native (*)(void)) symaddr;
  476.         printf("Result: %#zx\n", f());
  477.     }
  478.    
  479.     return 1;
  480. }
  481.  
  482. /** Call function with one parameter */
  483. int cmd_call1(cmd_arg_t *argv)
  484. {
  485.     __address symaddr;
  486.     char *symbol;
  487.     __native (*f)(__native,...);
  488.     __native arg1 = argv[1].intval;
  489.  
  490.     symaddr = get_symbol_addr(argv->buffer);
  491.     if (!symaddr)
  492.         printf("Symbol %s not found.\n", argv->buffer);
  493.     else if (symaddr == (__address) -1) {
  494.         symtab_print_search(argv->buffer);
  495.         printf("Duplicate symbol, be more specific.\n");
  496.     } else {
  497.         symbol = get_symtab_entry(symaddr);
  498.         printf("Calling f(0x%zX): %.*p: %s\n", arg1, sizeof(__address) * 2, symaddr, symbol);
  499.         f =  (__native (*)(__native,...)) symaddr;
  500.         printf("Result: %#zx\n", f(arg1));
  501.     }
  502.    
  503.     return 1;
  504. }
  505.  
  506. /** Call function with two parameters */
  507. int cmd_call2(cmd_arg_t *argv)
  508. {
  509.     __address symaddr;
  510.     char *symbol;
  511.     __native (*f)(__native,__native,...);
  512.     __native arg1 = argv[1].intval;
  513.     __native arg2 = argv[2].intval;
  514.  
  515.     symaddr = get_symbol_addr(argv->buffer);
  516.     if (!symaddr)
  517.         printf("Symbol %s not found.\n", argv->buffer);
  518.     else if (symaddr == (__address) -1) {
  519.         symtab_print_search(argv->buffer);
  520.         printf("Duplicate symbol, be more specific.\n");
  521.     } else {
  522.         symbol = get_symtab_entry(symaddr);
  523.         printf("Calling f(0x%zx,0x%zx): %.*p: %s\n",
  524.                arg1, arg2, sizeof(__address) * 2, symaddr, symbol);
  525.         f =  (__native (*)(__native,__native,...)) symaddr;
  526.         printf("Result: %#zx\n", f(arg1, arg2));
  527.     }
  528.    
  529.     return 1;
  530. }
  531.  
  532. /** Call function with three parameters */
  533. int cmd_call3(cmd_arg_t *argv)
  534. {
  535.     __address symaddr;
  536.     char *symbol;
  537.     __native (*f)(__native,__native,__native,...);
  538.     __native arg1 = argv[1].intval;
  539.     __native arg2 = argv[2].intval;
  540.     __native arg3 = argv[3].intval;
  541.  
  542.     symaddr = get_symbol_addr(argv->buffer);
  543.     if (!symaddr)
  544.         printf("Symbol %s not found.\n", argv->buffer);
  545.     else if (symaddr == (__address) -1) {
  546.         symtab_print_search(argv->buffer);
  547.         printf("Duplicate symbol, be more specific.\n");
  548.     } else {
  549.         symbol = get_symtab_entry(symaddr);
  550.         printf("Calling f(0x%zx,0x%zx, 0x%zx): %.*p: %s\n",
  551.                arg1, arg2, arg3, sizeof(__address) * 2, symaddr, symbol);
  552.         f =  (__native (*)(__native,__native,__native,...)) symaddr;
  553.         printf("Result: %#zx\n", f(arg1, arg2, arg3));
  554.     }
  555.    
  556.     return 1;
  557. }
  558.  
  559.  
  560. /** Print detailed description of 'describe' command. */
  561. void desc_help(void)
  562. {
  563.     printf("Syntax: describe command_name\n");
  564. }
  565.  
  566. /** Halt the kernel.
  567.  *
  568.  * @param argv Argument vector (ignored).
  569.  *
  570.  * @return 0 on failure, 1 on success (never returns).
  571.  */
  572. int cmd_halt(cmd_arg_t *argv)
  573. {
  574.     halt();
  575.     return 1;
  576. }
  577.  
  578. /** Command for printing TLB contents.
  579.  *
  580.  * @param argv Not used.
  581.  *
  582.  * @return Always returns 1.
  583.  */
  584. int cmd_tlb(cmd_arg_t *argv)
  585. {
  586.     tlb_print();
  587.     return 1;
  588. }
  589.  
  590. /** Write 4 byte value to address */
  591. int cmd_set4(cmd_arg_t *argv)
  592. {
  593.     __u32 *addr ;
  594.     __u32 arg1 = argv[1].intval;
  595.     bool pointer = false;
  596.  
  597.     if (((char *)argv->buffer)[0] == '*') {
  598.         addr = (__u32 *) get_symbol_addr(argv->buffer+1);
  599.         pointer = true;
  600.     } else if (((char *)argv->buffer)[0] >= '0' &&
  601.            ((char *)argv->buffer)[0] <= '9')
  602.         addr = (__u32 *)atoi((char *)argv->buffer);
  603.     else
  604.         addr = (__u32 *)get_symbol_addr(argv->buffer);
  605.  
  606.     if (!addr)
  607.         printf("Symbol %s not found.\n", argv->buffer);
  608.     else if (addr == (__u32 *) -1) {
  609.         symtab_print_search(argv->buffer);
  610.         printf("Duplicate symbol, be more specific.\n");
  611.     } else {
  612.         if (pointer)
  613.             addr = (__u32 *)(*(__native *)addr);
  614.         printf("Writing 0x%x -> %.*p\n", arg1, sizeof(__address) * 2, addr);
  615.         *addr = arg1;
  616.        
  617.     }
  618.    
  619.     return 1;
  620. }
  621.  
  622. /** Command for listings SLAB caches
  623.  *
  624.  * @param argv Ignores
  625.  *
  626.  * @return Always 1
  627.  */
  628. int cmd_slabs(cmd_arg_t * argv) {
  629.     slab_print_list();
  630.     return 1;
  631. }
  632.  
  633.  
  634. /** Command for listings Thread information
  635.  *
  636.  * @param argv Ignores
  637.  *
  638.  * @return Always 1
  639.  */
  640. int cmd_threads(cmd_arg_t * argv) {
  641.     thread_print_list();
  642.     return 1;
  643. }
  644.  
  645. /** Command for listings Task information
  646.  *
  647.  * @param argv Ignores
  648.  *
  649.  * @return Always 1
  650.  */
  651. int cmd_tasks(cmd_arg_t * argv) {
  652.     task_print_list();
  653.     return 1;
  654. }
  655.  
  656. /** Command for listings Thread information
  657.  *
  658.  * @param argv Ignores
  659.  *
  660.  * @return Always 1
  661.  */
  662. int cmd_sched(cmd_arg_t * argv) {
  663.     sched_print_list();
  664.     return 1;
  665. }
  666.  
  667. /** Command for listing memory zones
  668.  *
  669.  * @param argv Ignored
  670.  *
  671.  * return Always 1
  672.  */
  673. int cmd_zones(cmd_arg_t * argv) {
  674.     zone_print_list();
  675.     return 1;
  676. }
  677.  
  678. /** Command for memory zone details
  679.  *
  680.  * @param argv Integer argument from cmdline expected
  681.  *
  682.  * return Always 1
  683.  */
  684. int cmd_zone(cmd_arg_t * argv) {
  685.     zone_print_one(argv[0].intval);
  686.     return 1;
  687. }
  688.  
  689. /** Command for listing processors.
  690.  *
  691.  * @param argv Ignored.
  692.  *
  693.  * return Always 1.
  694.  */
  695. int cmd_cpus(cmd_arg_t *argv)
  696. {
  697.     cpu_list();
  698.     return 1;
  699. }
  700.  
  701. /** Command for printing kernel version.
  702.  *
  703.  * @param argv Ignored.
  704.  *
  705.  * return Always 1.
  706.  */
  707. int cmd_version(cmd_arg_t *argv)
  708. {
  709.     version_print();
  710.     return 1;
  711. }
  712.  
  713. /** Command for returning console back to userspace.
  714.  *
  715.  * @param argv Ignored.
  716.  *
  717.  * return Always 1.
  718.  */
  719. int cmd_continue(cmd_arg_t *argv)
  720. {
  721.     arch_release_console();
  722.     return 1;
  723. }
  724.