Subversion Repositories HelenOS-historic

Rev

Rev 512 | Go to most recent revision | Blame | 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 <main/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.  
  41. #define MAX_CMDLINE 256
  42.  
  43. /** Simple kernel console.
  44.  *
  45.  * The console is realized by kernel thread kconsole.
  46.  * It doesn't understand any commands on its own, but
  47.  * makes it possible for other kernel subsystems to
  48.  * register their own commands.
  49.  */
  50.  
  51. /** Locking.
  52.  *
  53.  * There is a list of cmd_info_t structures. This list
  54.  * is protected by cmd_lock spinlock. Note that specially
  55.  * the link elements of cmd_info_t are protected by
  56.  * this lock.
  57.  *
  58.  * Each cmd_info_t also has its own lock, which protects
  59.  * all elements thereof except the link element.
  60.  *
  61.  * cmd_lock must be acquired before any cmd_info lock.
  62.  * When locking two cmd info structures, structure with
  63.  * lower address must be locked first.
  64.  */
  65.  
  66. spinlock_t cmd_lock;    /**< Lock protecting command list. */
  67. link_t cmd_head;    /**< Command list. */
  68.  
  69. static cmd_info_t *parse_cmdline(char *cmdline, size_t len);
  70. static int cmd_help(cmd_arg_t *cmd);
  71.  
  72. static cmd_info_t help_info;
  73.  
  74. /** Initialize kconsole data structures. */
  75. void kconsole_init(void)
  76. {
  77.     spinlock_initialize(&cmd_lock);
  78.     list_initialize(&cmd_head);
  79.    
  80.     help_info.name = "help";
  81.     help_info.description = "List supported commands.";
  82.     help_info.func = cmd_help;
  83.     help_info.argc = 0;
  84.     help_info.argv = NULL;
  85.    
  86.     spinlock_initialize(&help_info.lock);
  87.     link_initialize(&help_info.link);
  88.    
  89.     if (!cmd_register(&help_info))
  90.         panic("could not register command\n");
  91. }
  92.  
  93.  
  94. /** Register kconsole command.
  95.  *
  96.  * @param cmd Structure describing the command.
  97.  *
  98.  * @return 0 on failure, 1 on success.
  99.  */
  100. int cmd_register(cmd_info_t *cmd)
  101. {
  102.     ipl_t ipl;
  103.     link_t *cur;
  104.    
  105.     ipl = interrupts_disable();
  106.     spinlock_lock(&cmd_lock);
  107.    
  108.     /*
  109.      * Make sure the command is not already listed.
  110.      */
  111.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  112.         cmd_info_t *hlp;
  113.        
  114.         hlp = list_get_instance(cur, cmd_info_t, link);
  115.  
  116.         if (hlp == cmd) {
  117.             /* The command is already there. */
  118.             spinlock_unlock(&cmd_lock);
  119.             interrupts_restore(ipl);
  120.             return 0;
  121.         }
  122.  
  123.         /* Avoid deadlock. */
  124.         if (hlp < cmd) {
  125.             spinlock_lock(&hlp->lock);
  126.             spinlock_lock(&cmd->lock);
  127.         } else {
  128.             spinlock_lock(&cmd->lock);
  129.             spinlock_lock(&hlp->lock);
  130.         }
  131.        
  132.         if ((strcmp(hlp->name, cmd->name, strlen(cmd->name)) == 0)) {
  133.             /* The command is already there. */
  134.             spinlock_unlock(&hlp->lock);
  135.             spinlock_unlock(&cmd->lock);
  136.             spinlock_unlock(&cmd_lock);
  137.             interrupts_restore(ipl);
  138.             return 0;
  139.         }
  140.        
  141.         spinlock_unlock(&hlp->lock);
  142.         spinlock_unlock(&cmd->lock);
  143.     }
  144.    
  145.     /*
  146.      * Now the command can be added.
  147.      */
  148.     list_append(&cmd->link, &cmd_head);
  149.    
  150.     spinlock_unlock(&cmd_lock);
  151.     interrupts_restore(ipl);
  152.     return 1;
  153. }
  154.  
  155. /** Kernel console managing thread.
  156.  *
  157.  * @param arg Not used.
  158.  */
  159. void kconsole(void *arg)
  160. {
  161.     char cmdline[MAX_CMDLINE+1];
  162.     cmd_info_t *cmd_info;
  163.     count_t len;
  164.  
  165.     if (!stdin) {
  166.         printf("%s: no stdin\n", __FUNCTION__);
  167.         return;
  168.     }
  169.    
  170.     while (true) {
  171.         printf("%s> ", __FUNCTION__);
  172.         len = gets(stdin, cmdline, sizeof(cmdline));
  173.         cmdline[len] = '\0';
  174.         cmd_info = parse_cmdline(cmdline, len);
  175.         if (!cmd_info) {
  176.             printf("?\n");
  177.             continue;
  178.         }
  179.         (void) cmd_info->func(cmd_info->argv);
  180.     }
  181. }
  182.  
  183. /** Parse command line.
  184.  *
  185.  * @param cmdline Command line as read from input device.
  186.  * @param len Command line length.
  187.  *
  188.  * @return Structure describing the command.
  189.  */
  190. cmd_info_t *parse_cmdline(char *cmdline, size_t len)
  191. {
  192.     index_t start = 0, end = 0;
  193.     bool found_start = false;
  194.     cmd_info_t *cmd = NULL;
  195.     link_t *cur;
  196.     ipl_t ipl;
  197.     int i;
  198.    
  199.     for (i = 0; i < len; i++) {
  200.         if (!found_start) {
  201.             if (is_white(cmdline[i]))
  202.                 start++;
  203.             else
  204.                 found_start = true;
  205.         } else {
  206.             if (is_white(cmdline[i]))
  207.                 break;
  208.         }
  209.     }
  210.     end = i - 1;
  211.    
  212.     if (!found_start) {
  213.         /* Command line did not contain alphanumeric word. */
  214.         return NULL;
  215.     }
  216.  
  217.     ipl = interrupts_disable();
  218.     spinlock_lock(&cmd_lock);
  219.    
  220.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  221.         cmd_info_t *hlp;
  222.        
  223.         hlp = list_get_instance(cur, cmd_info_t, link);
  224.         spinlock_lock(&hlp->lock);
  225.        
  226.         if (strcmp(hlp->name, &cmdline[start], (end - start) + 1) == 0) {
  227.             cmd = hlp;
  228.             break;
  229.         }
  230.        
  231.         spinlock_unlock(&hlp->lock);
  232.     }
  233.    
  234.     spinlock_unlock(&cmd_lock);
  235.    
  236.     if (!cmd) {
  237.         /* Unknown command. */
  238.         interrupts_restore(ipl);
  239.         return NULL;
  240.     }
  241.  
  242.     /* cmd == hlp is locked */
  243.    
  244.     /*
  245.      * TODO:
  246.      * The command line must be further analyzed and
  247.      * the parameters therefrom must be matched and
  248.      * converted to those specified in the cmd info
  249.      * structure.
  250.      */
  251.    
  252.     spinlock_unlock(&cmd->lock);
  253.     interrupts_restore(ipl);
  254.     return cmd;
  255. }
  256.  
  257. /** List supported commands.
  258.  *
  259.  * @param cmd Argument vector.
  260.  *
  261.  * @return 0 on failure, 1 on success.
  262.  */
  263. int cmd_help(cmd_arg_t *cmd)
  264. {
  265.     link_t *cur;
  266.     ipl_t ipl;
  267.  
  268.     ipl = interrupts_disable();
  269.     spinlock_lock(&cmd_lock);
  270.    
  271.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  272.         cmd_info_t *hlp;
  273.        
  274.         hlp = list_get_instance(cur, cmd_info_t, link);
  275.         spinlock_lock(&hlp->lock);
  276.        
  277.         printf("%s\t%s\n", hlp->name, hlp->description);
  278.  
  279.         spinlock_unlock(&hlp->lock);
  280.     }
  281.    
  282.     spinlock_unlock(&cmd_lock);
  283.     interrupts_restore(ipl);
  284.  
  285.     return 1;
  286. }
  287.