Subversion Repositories HelenOS

Rev

Rev 589 | Rev 594 | 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. #include <console/kconsole.h>
  30. #include <console/console.h>
  31. #include <console/chardev.h>
  32. #include <print.h>
  33. #include <panic.h>
  34. #include <typedefs.h>
  35. #include <arch/types.h>
  36. #include <list.h>
  37. #include <arch.h>
  38. #include <func.h>
  39. #include <macros.h>
  40. #include <debug.h>
  41. #include <symtab.h>
  42.  
  43. #define MAX_CMDLINE 256
  44.  
  45. /** Simple kernel console.
  46.  *
  47.  * The console is realized by kernel thread kconsole.
  48.  * It doesn't understand any useful command on its own,
  49.  * but makes it possible for other kernel subsystems to
  50.  * register their own commands.
  51.  */
  52.  
  53. /** Locking.
  54.  *
  55.  * There is a list of cmd_info_t structures. This list
  56.  * is protected by cmd_lock spinlock. Note that specially
  57.  * the link elements of cmd_info_t are protected by
  58.  * this lock.
  59.  *
  60.  * Each cmd_info_t also has its own lock, which protects
  61.  * all elements thereof except the link element.
  62.  *
  63.  * cmd_lock must be acquired before any cmd_info lock.
  64.  * When locking two cmd info structures, structure with
  65.  * lower address must be locked first.
  66.  */
  67.  
  68. spinlock_t cmd_lock;    /**< Lock protecting command list. */
  69. link_t cmd_head;    /**< Command list. */
  70.  
  71. static cmd_info_t *parse_cmdline(char *cmdline, size_t len);
  72. static bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end);
  73.  
  74. /** Data and methods for 'help' command. */
  75. static int cmd_help(cmd_arg_t *argv);
  76. static cmd_info_t help_info = {
  77.     .name = "help",
  78.     .description = "List of supported commands.",
  79.     .func = cmd_help,
  80.     .argc = 0
  81. };
  82.  
  83. /** Data and methods for 'description' command. */
  84. static int cmd_desc(cmd_arg_t *argv);
  85. static void desc_help(void);
  86. static char desc_buf[MAX_CMDLINE+1];
  87. static cmd_arg_t desc_argv = {
  88.     .type = ARG_TYPE_STRING,
  89.     .buffer = desc_buf,
  90.     .len = sizeof(desc_buf)
  91. };
  92. static cmd_info_t desc_info = {
  93.     .name = "describe",
  94.     .description = "Describe specified command.",
  95.     .help = desc_help,
  96.     .func = cmd_desc,
  97.     .argc = 1,
  98.     .argv = &desc_argv
  99. };
  100.  
  101. /** Data and methods for 'symaddr' command. */
  102. static int cmd_symaddr(cmd_arg_t *argv);
  103. static char symaddr_buf[MAX_CMDLINE+1];
  104. static cmd_arg_t symaddr_argv = {
  105.     .type = ARG_TYPE_STRING,
  106.     .buffer = symaddr_buf,
  107.     .len = sizeof(symaddr_buf)
  108. };
  109. static cmd_info_t symaddr_info = {
  110.     .name = "symaddr",
  111.     .description = "Return symbol address.",
  112.     .func = cmd_symaddr,
  113.     .argc = 1,
  114.     .argv = &symaddr_argv
  115. };
  116.  
  117. /** Call0 - call function with no parameters */
  118. static char call0_buf[MAX_CMDLINE+1];
  119. static char carg1_buf[MAX_CMDLINE+1];
  120. static char carg2_buf[MAX_CMDLINE+1];
  121. static char carg3_buf[MAX_CMDLINE+1];
  122.  
  123. static int cmd_call0(cmd_arg_t *argv);
  124. static cmd_arg_t call0_argv = {
  125.     .type = ARG_TYPE_STRING,
  126.     .buffer = call0_buf,
  127.     .len = sizeof(call0_buf)
  128. };
  129. static cmd_info_t call0_info = {
  130.     .name = "call0",
  131.     .description = "call0 <function> -> call function().",
  132.     .func = cmd_call0,
  133.     .argc = 1,
  134.     .argv = &call0_argv
  135. };
  136.  
  137. static int cmd_call1(cmd_arg_t *argv);
  138. static cmd_arg_t call1_argv[] = {
  139.     {
  140.         .type = ARG_TYPE_STRING,
  141.         .buffer = call0_buf,
  142.         .len = sizeof(call0_buf)
  143.     },
  144.     {
  145.         .type = ARG_TYPE_VAR,
  146.         .buffer = carg1_buf,
  147.         .len = sizeof(carg1_buf)
  148.     }
  149. };
  150. static cmd_info_t call1_info = {
  151.     .name = "call1",
  152.     .description = "call1 <function> <arg1> -> call function(arg1).",
  153.     .func = cmd_call1,
  154.     .argc = 2,
  155.     .argv = call1_argv
  156. };
  157.  
  158. static int cmd_call2(cmd_arg_t *argv);
  159. static cmd_arg_t call2_argv[] = {
  160.     {
  161.         .type = ARG_TYPE_STRING,
  162.         .buffer = call0_buf,
  163.         .len = sizeof(call0_buf)
  164.     },
  165.     {
  166.         .type = ARG_TYPE_VAR,
  167.         .buffer = carg1_buf,
  168.         .len = sizeof(carg1_buf)
  169.     },
  170.     {
  171.         .type = ARG_TYPE_VAR,
  172.         .buffer = carg2_buf,
  173.         .len = sizeof(carg2_buf)
  174.     }
  175. };
  176. static cmd_info_t call2_info = {
  177.     .name = "call2",
  178.     .description = "call2 <function> <arg1> <arg2> -> call function(arg1,arg2).",
  179.     .func = cmd_call2,
  180.     .argc = 3,
  181.     .argv = call2_argv
  182. };
  183.  
  184. static int cmd_call3(cmd_arg_t *argv);
  185. static cmd_arg_t call3_argv[] = {
  186.     {
  187.         .type = ARG_TYPE_STRING,
  188.         .buffer = call0_buf,
  189.         .len = sizeof(call0_buf)
  190.     },
  191.     {
  192.         .type = ARG_TYPE_VAR,
  193.         .buffer = carg1_buf,
  194.         .len = sizeof(carg1_buf)
  195.     },
  196.     {
  197.         .type = ARG_TYPE_VAR,
  198.         .buffer = carg2_buf,
  199.         .len = sizeof(carg2_buf)
  200.     },
  201.     {
  202.         .type = ARG_TYPE_VAR,
  203.         .buffer = carg3_buf,
  204.         .len = sizeof(carg3_buf)
  205.     }
  206.  
  207. };
  208. static cmd_info_t call3_info = {
  209.     .name = "call3",
  210.     .description = "call3 <function> <arg1> <arg2> <arg3> -> call function(arg1,arg2,arg3).",
  211.     .func = cmd_call3,
  212.     .argc = 4,
  213.     .argv = call3_argv
  214. };
  215.  
  216. /** Data and methods for 'halt' command. */
  217. static int cmd_halt(cmd_arg_t *argv);
  218. static cmd_info_t halt_info = {
  219.     .name = "halt",
  220.     .description = "Halt the kernel.",
  221.     .func = cmd_halt,
  222.     .argc = 0
  223. };
  224.  
  225. /** Initialize kconsole data structures. */
  226. void kconsole_init(void)
  227. {
  228.     spinlock_initialize(&cmd_lock, "kconsole_cmd");
  229.     list_initialize(&cmd_head);
  230.    
  231.     spinlock_initialize(&help_info.lock, "kconsole_help");
  232.     link_initialize(&help_info.link);
  233.     if (!cmd_register(&help_info))
  234.         panic("could not register command %s\n", help_info.name);
  235.  
  236.  
  237.     spinlock_initialize(&desc_info.lock, "kconsole_desc");
  238.     link_initialize(&desc_info.link);
  239.     if (!cmd_register(&desc_info))
  240.         panic("could not register command %s\n", desc_info.name);
  241.    
  242.     spinlock_initialize(&symaddr_info.lock, "kconsole_symaddr");
  243.     link_initialize(&symaddr_info.link);
  244.     if (!cmd_register(&symaddr_info))
  245.         panic("could not register command %s\n", symaddr_info.name);
  246.  
  247.     spinlock_initialize(&call0_info.lock, "kconsole_call0");
  248.     link_initialize(&call0_info.link);
  249.     if (!cmd_register(&call0_info))
  250.         panic("could not register command %s\n", call0_info.name);
  251.  
  252.     spinlock_initialize(&call1_info.lock, "kconsole_call1");
  253.     link_initialize(&call1_info.link);
  254.     if (!cmd_register(&call1_info))
  255.         panic("could not register command %s\n", call1_info.name);
  256.  
  257.  
  258.     spinlock_initialize(&call2_info.lock, "kconsole_call2");
  259.     link_initialize(&call2_info.link);
  260.     if (!cmd_register(&call2_info))
  261.         panic("could not register command %s\n", call2_info.name);
  262.  
  263.     spinlock_initialize(&call3_info.lock, "kconsole_call3");
  264.     link_initialize(&call3_info.link);
  265.     if (!cmd_register(&call3_info))
  266.         panic("could not register command %s\n", call3_info.name);
  267.    
  268.     spinlock_initialize(&halt_info.lock, "kconsole_halt");
  269.     link_initialize(&halt_info.link);
  270.     if (!cmd_register(&halt_info))
  271.         panic("could not register command %s\n", halt_info.name);
  272. }
  273.  
  274.  
  275. /** Register kconsole command.
  276.  *
  277.  * @param cmd Structure describing the command.
  278.  *
  279.  * @return 0 on failure, 1 on success.
  280.  */
  281. int cmd_register(cmd_info_t *cmd)
  282. {
  283.     ipl_t ipl;
  284.     link_t *cur;
  285.    
  286.     spinlock_lock(&cmd_lock);
  287.    
  288.     /*
  289.      * Make sure the command is not already listed.
  290.      */
  291.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  292.         cmd_info_t *hlp;
  293.        
  294.         hlp = list_get_instance(cur, cmd_info_t, link);
  295.  
  296.         if (hlp == cmd) {
  297.             /* The command is already there. */
  298.             spinlock_unlock(&cmd_lock);
  299.             return 0;
  300.         }
  301.  
  302.         /* Avoid deadlock. */
  303.         if (hlp < cmd) {
  304.             spinlock_lock(&hlp->lock);
  305.             spinlock_lock(&cmd->lock);
  306.         } else {
  307.             spinlock_lock(&cmd->lock);
  308.             spinlock_lock(&hlp->lock);
  309.         }
  310.        
  311.         if ((strncmp(hlp->name, cmd->name, strlen(cmd->name)) == 0)) {
  312.             /* The command is already there. */
  313.             spinlock_unlock(&hlp->lock);
  314.             spinlock_unlock(&cmd->lock);
  315.             spinlock_unlock(&cmd_lock);
  316.             return 0;
  317.         }
  318.        
  319.         spinlock_unlock(&hlp->lock);
  320.         spinlock_unlock(&cmd->lock);
  321.     }
  322.    
  323.     /*
  324.      * Now the command can be added.
  325.      */
  326.     list_append(&cmd->link, &cmd_head);
  327.    
  328.     spinlock_unlock(&cmd_lock);
  329.     return 1;
  330. }
  331.  
  332. /** Kernel console managing thread.
  333.  *
  334.  * @param arg Not used.
  335.  */
  336. void kconsole(void *arg)
  337. {
  338.     char cmdline[MAX_CMDLINE+1];
  339.     cmd_info_t *cmd_info;
  340.     count_t len;
  341.  
  342.     if (!stdin) {
  343.         printf("%s: no stdin\n", __FUNCTION__);
  344.         return;
  345.     }
  346.    
  347.     while (true) {
  348.         printf("%s> ", __FUNCTION__);
  349.         if (!(len = gets(stdin, cmdline, sizeof(cmdline))))
  350.             continue;
  351.         cmdline[len] = '\0';
  352.         cmd_info = parse_cmdline(cmdline, len);
  353.         if (!cmd_info)
  354.             continue;
  355.         (void) cmd_info->func(cmd_info->argv);
  356.     }
  357. }
  358.  
  359. static int parse_int_arg(char *text, size_t len, __native *result)
  360. {
  361.     char symname[MAX_SYMBOL_NAME];
  362.     __address symaddr;
  363.     bool isaddr = false;
  364.     bool isptr = false;
  365.    
  366.     /* If we get a name, try to find it in symbol table */
  367.     if (text[0] < '0' | text[0] > '9') {
  368.         if (text[0] == '&') {
  369.             isaddr = true;
  370.             text++;len--;
  371.         } else if (text[0] == '*') {
  372.             isptr = true;
  373.             text++;len--;
  374.         }
  375.         strncpy(symname, text, min(len+1, MAX_SYMBOL_NAME));
  376.         symaddr = get_symbol_addr(symname);
  377.         if (!symaddr) {
  378.             printf("Symbol %s not found.\n",symname);
  379.             return -1;
  380.         }
  381.         if (symaddr == (__address) -1) {
  382.             printf("Duplicate symbol %s.\n",symname);
  383.             symtab_print_search(symname);
  384.             return -1;
  385.         }
  386.         if (isaddr)
  387.             *result = (__native)symaddr;
  388.         else if (isptr)
  389.             *result = **((__native **)symaddr);
  390.         else
  391.             *result = *((__native *)symaddr);
  392.     } else /* It's a number - convert it */
  393.         *result = atoi(text);
  394.     return 0;
  395. }
  396.  
  397. /** Parse command line.
  398.  *
  399.  * @param cmdline Command line as read from input device.
  400.  * @param len Command line length.
  401.  *
  402.  * @return Structure describing the command.
  403.  */
  404. cmd_info_t *parse_cmdline(char *cmdline, size_t len)
  405. {
  406.     index_t start = 0, end = 0;
  407.     cmd_info_t *cmd = NULL;
  408.     link_t *cur;
  409.     ipl_t ipl;
  410.     int i;
  411.    
  412.     if (!parse_argument(cmdline, len, &start, &end)) {
  413.         /* Command line did not contain alphanumeric word. */
  414.         return NULL;
  415.     }
  416.  
  417.     spinlock_lock(&cmd_lock);
  418.    
  419.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  420.         cmd_info_t *hlp;
  421.        
  422.         hlp = list_get_instance(cur, cmd_info_t, link);
  423.         spinlock_lock(&hlp->lock);
  424.        
  425.         if (strncmp(hlp->name, &cmdline[start], (end - start) + 1) == 0) {
  426.             cmd = hlp;
  427.             break;
  428.         }
  429.        
  430.         spinlock_unlock(&hlp->lock);
  431.     }
  432.    
  433.     spinlock_unlock(&cmd_lock);
  434.    
  435.     if (!cmd) {
  436.         /* Unknown command. */
  437.         printf("Unknown command.\n");
  438.         return NULL;
  439.     }
  440.  
  441.     /* cmd == hlp is locked */
  442.    
  443.     /*
  444.      * The command line must be further analyzed and
  445.      * the parameters therefrom must be matched and
  446.      * converted to those specified in the cmd info
  447.      * structure.
  448.      */
  449.  
  450.     for (i = 0; i < cmd->argc; i++) {
  451.         char *buf;
  452.         start = end + 1;
  453.         if (!parse_argument(cmdline, len, &start, &end)) {
  454.             printf("Too few arguments.\n");
  455.             spinlock_unlock(&cmd->lock);
  456.             return NULL;
  457.         }
  458.        
  459.         switch (cmd->argv[i].type) {
  460.         case ARG_TYPE_STRING:
  461.                 buf = cmd->argv[i].buffer;
  462.                 strncpy(buf, (const char *) &cmdline[start], min((end - start) + 2, cmd->argv[i].len));
  463.             buf[min((end - start) + 1, cmd->argv[i].len - 1)] = '\0';
  464.             break;
  465.         case ARG_TYPE_INT:
  466.             if (parse_int_arg(cmdline+start, end-start+1,
  467.                       &cmd->argv[i].intval))
  468.                 return NULL;
  469.             break;
  470.         case ARG_TYPE_VAR:
  471.             if (start != end && cmdline[start] == '"' && cmdline[end] == '"') {
  472.                 buf = cmd->argv[i].buffer;
  473.                 strncpy(buf, (const char *) &cmdline[start+1],
  474.                     min((end-start), cmd->argv[i].len));
  475.                 buf[min((end - start), cmd->argv[i].len - 1)] = '\0';
  476.                 cmd->argv[i].intval = (__native) buf;
  477.                 cmd->argv[i].vartype = ARG_TYPE_STRING;
  478.             } else if (!parse_int_arg(cmdline+start, end-start+1,
  479.                          &cmd->argv[i].intval))
  480.                 cmd->argv[i].vartype = ARG_TYPE_INT;
  481.             else {
  482.                 printf("Unrecognized variable argument.\n");
  483.                 return NULL;
  484.             }
  485.             break;
  486.         case ARG_TYPE_INVALID:
  487.         default:
  488.             printf("invalid argument type\n");
  489.             return NULL;
  490.             break;
  491.         }
  492.     }
  493.    
  494.     start = end + 1;
  495.     if (parse_argument(cmdline, len, &start, &end)) {
  496.         printf("Too many arguments.\n");
  497.         spinlock_unlock(&cmd->lock);
  498.         return NULL;
  499.     }
  500.    
  501.     spinlock_unlock(&cmd->lock);
  502.     return cmd;
  503. }
  504.  
  505. /** Parse argument.
  506.  *
  507.  * Find start and end positions of command line argument.
  508.  *
  509.  * @param cmdline Command line as read from the input device.
  510.  * @param len Number of characters in cmdline.
  511.  * @param start On entry, 'start' contains pointer to the index
  512.  *        of first unprocessed character of cmdline.
  513.  *        On successful exit, it marks beginning of the next argument.
  514.  * @param end Undefined on entry. On exit, 'end' points to the last character
  515.  *        of the next argument.
  516.  *
  517.  * @return false on failure, true on success.
  518.  */
  519. bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end)
  520. {
  521.     int i;
  522.     bool found_start = false;
  523.    
  524.     ASSERT(start != NULL);
  525.     ASSERT(end != NULL);
  526.    
  527.     for (i = *start; i < len; i++) {
  528.         if (!found_start) {
  529.             if (is_white(cmdline[i]))
  530.                 (*start)++;
  531.             else
  532.                 found_start = true;
  533.         } else {
  534.             if (is_white(cmdline[i]))
  535.                 break;
  536.         }
  537.     }
  538.     *end = i - 1;
  539.  
  540.     return found_start;
  541. }
  542.  
  543.  
  544. /** List supported commands.
  545.  *
  546.  * @param argv Argument vector.
  547.  *
  548.  * @return 0 on failure, 1 on success.
  549.  */
  550. int cmd_help(cmd_arg_t *argv)
  551. {
  552.     link_t *cur;
  553.     ipl_t ipl;
  554.  
  555.     spinlock_lock(&cmd_lock);
  556.    
  557.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  558.         cmd_info_t *hlp;
  559.        
  560.         hlp = list_get_instance(cur, cmd_info_t, link);
  561.         spinlock_lock(&hlp->lock);
  562.        
  563.         printf("%s - %s\n", hlp->name, hlp->description);
  564.  
  565.         spinlock_unlock(&hlp->lock);
  566.     }
  567.    
  568.     spinlock_unlock(&cmd_lock);
  569.  
  570.     return 1;
  571. }
  572.  
  573. /** Describe specified command.
  574.  *
  575.  * @param argv Argument vector.
  576.  *
  577.  * @return 0 on failure, 1 on success.
  578.  */
  579. int cmd_desc(cmd_arg_t *argv)
  580. {
  581.     link_t *cur;
  582.     ipl_t ipl;
  583.  
  584.     spinlock_lock(&cmd_lock);
  585.    
  586.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  587.         cmd_info_t *hlp;
  588.        
  589.         hlp = list_get_instance(cur, cmd_info_t, link);
  590.         spinlock_lock(&hlp->lock);
  591.  
  592.         if (strncmp(hlp->name, (const char *) argv->buffer, strlen(hlp->name)) == 0) {
  593.             printf("%s - %s\n", hlp->name, hlp->description);
  594.             if (hlp->help)
  595.                 hlp->help();
  596.             spinlock_unlock(&hlp->lock);
  597.             break;
  598.         }
  599.  
  600.         spinlock_unlock(&hlp->lock);
  601.     }
  602.    
  603.     spinlock_unlock(&cmd_lock);
  604.  
  605.     return 1;
  606. }
  607.  
  608. /** Search symbol table */
  609. int cmd_symaddr(cmd_arg_t *argv)
  610. {
  611.     __address symaddr;
  612.     char *symbol;
  613.  
  614.     symtab_print_search(argv->buffer);
  615.    
  616.     return 1;
  617. }
  618.  
  619. /** Call function with zero parameters */
  620. int cmd_call0(cmd_arg_t *argv)
  621. {
  622.     __address symaddr;
  623.     char *symbol;
  624.     __native (*f)(void);
  625.  
  626.     symaddr = get_symbol_addr(argv->buffer);
  627.     if (!symaddr)
  628.         printf("Symbol %s not found.\n", argv->buffer);
  629.     else if (symaddr == (__address) -1) {
  630.         symtab_print_search(argv->buffer);
  631.         printf("Duplicate symbol, be more specific.\n");
  632.     } else {
  633.         symbol = get_symtab_entry(symaddr);
  634.         printf("Calling f(): 0x%p: %s\n", symaddr, symbol);
  635.         f =  (__native (*)(void)) symaddr;
  636.         printf("Result: 0x%X\n", f());
  637.     }
  638.    
  639.     return 1;
  640. }
  641.  
  642. /** Call function with one parameter */
  643. int cmd_call1(cmd_arg_t *argv)
  644. {
  645.     __address symaddr;
  646.     char *symbol;
  647.     __native (*f)(__native);
  648.     __native arg1 = argv[1].intval;
  649.  
  650.     symaddr = get_symbol_addr(argv->buffer);
  651.     if (!symaddr)
  652.         printf("Symbol %s not found.\n", argv->buffer);
  653.     else if (symaddr == (__address) -1) {
  654.         symtab_print_search(argv->buffer);
  655.         printf("Duplicate symbol, be more specific.\n");
  656.     } else {
  657.         symbol = get_symtab_entry(symaddr);
  658.         printf("Calling f(0x%x): 0x%p: %s\n", arg1, symaddr, symbol);
  659.         f =  (__native (*)(__native)) symaddr;
  660.         printf("Result: 0x%x\n", f(arg1));
  661.     }
  662.    
  663.     return 1;
  664. }
  665.  
  666. /** Call function with two parameters */
  667. int cmd_call2(cmd_arg_t *argv)
  668. {
  669.     __address symaddr;
  670.     char *symbol;
  671.     __native (*f)(__native,__native);
  672.     __native arg1 = argv[1].intval;
  673.     __native arg2 = argv[2].intval;
  674.  
  675.     symaddr = get_symbol_addr(argv->buffer);
  676.     if (!symaddr)
  677.         printf("Symbol %s not found.\n", argv->buffer);
  678.     else if (symaddr == (__address) -1) {
  679.         symtab_print_search(argv->buffer);
  680.         printf("Duplicate symbol, be more specific.\n");
  681.     } else {
  682.         symbol = get_symtab_entry(symaddr);
  683.         printf("Calling f(0x%x,0x%x): 0x%p: %s\n",
  684.                arg1, arg2, symaddr, symbol);
  685.         f =  (__native (*)(__native,__native)) symaddr;
  686.         printf("Result: 0x%x\n", f(arg1, arg2));
  687.     }
  688.    
  689.     return 1;
  690. }
  691.  
  692. /** Call function with three parameters */
  693. int cmd_call3(cmd_arg_t *argv)
  694. {
  695.     __address symaddr;
  696.     char *symbol;
  697.     __native (*f)(__native,__native,__native);
  698.     __native arg1 = argv[1].intval;
  699.     __native arg2 = argv[2].intval;
  700.     __native arg3 = argv[3].intval;
  701.  
  702.     symaddr = get_symbol_addr(argv->buffer);
  703.     if (!symaddr)
  704.         printf("Symbol %s not found.\n", argv->buffer);
  705.     else if (symaddr == (__address) -1) {
  706.         symtab_print_search(argv->buffer);
  707.         printf("Duplicate symbol, be more specific.\n");
  708.     } else {
  709.         symbol = get_symtab_entry(symaddr);
  710.         printf("Calling f(0x%x,0x%x, 0x%x): 0x%p: %s\n",
  711.                arg1, arg2, arg3, symaddr, symbol);
  712.         f =  (__native (*)(__native,__native,__native)) symaddr;
  713.         printf("Result: 0x%x\n", f(arg1, arg2, arg3));
  714.     }
  715.    
  716.     return 1;
  717. }
  718.  
  719.  
  720. /** Print detailed description of 'describe' command. */
  721. void desc_help(void)
  722. {
  723.     printf("Syntax: describe command_name\n");
  724. }
  725.  
  726. /** Halt the kernel.
  727.  *
  728.  * @param argv Argument vector (ignored).
  729.  *
  730.  * @return 0 on failure, 1 on success (never returns).
  731.  */
  732. int cmd_halt(cmd_arg_t *argv)
  733. {
  734.     halt();
  735.     return 1;
  736. }
  737.