Rev 512 | Rev 518 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 512 | Rev 517 | ||
---|---|---|---|
Line 28... | Line 28... | ||
28 | 28 | ||
29 | #include <main/kconsole.h> |
29 | #include <main/kconsole.h> |
30 | #include <console/console.h> |
30 | #include <console/console.h> |
31 | #include <console/chardev.h> |
31 | #include <console/chardev.h> |
32 | #include <print.h> |
32 | #include <print.h> |
- | 33 | #include <panic.h> |
|
33 | #include <typedefs.h> |
34 | #include <typedefs.h> |
34 | #include <arch/types.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 | } |
|
35 | 154 | ||
36 | /** Kernel console managing thread. |
155 | /** Kernel console managing thread. |
37 | * |
156 | * |
38 | * @param arg Not used. |
157 | * @param arg Not used. |
39 | */ |
158 | */ |
40 | void kconsole(void *arg) |
159 | void kconsole(void *arg) |
41 | { |
160 | { |
42 | __u8 buf[CHARDEV_BUFLEN]; |
161 | char cmdline[MAX_CMDLINE+1]; |
- | 162 | cmd_info_t *cmd_info; |
|
- | 163 | count_t len; |
|
43 | 164 | ||
44 | if (!stdin) { |
165 | if (!stdin) { |
45 | printf("%s: no stdin\n", __FUNCTION__); |
166 | printf("%s: no stdin\n", __FUNCTION__); |
46 | return; |
167 | return; |
47 | } |
168 | } |
48 | 169 | ||
49 | while (true) { |
170 | while (true) { |
50 | printf("%s> ", __FUNCTION__); |
171 | printf("%s> ", __FUNCTION__); |
51 | gets(stdin, buf, sizeof(buf)); |
172 | len = gets(stdin, cmdline, sizeof(cmdline)); |
- | 173 | cmdline[len] = '\0'; |
|
- | 174 | cmd_info = parse_cmdline(cmdline, len); |
|
- | 175 | if (!cmd_info) { |
|
52 | printf("?\n"); |
176 | printf("?\n"); |
- | 177 | continue; |
|
- | 178 | } |
|
- | 179 | (void) cmd_info->func(cmd_info->argv); |
|
53 | } |
180 | } |
54 | } |
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 | } |