source: mainline/generic/src/console/kconsole.c@ d43d2f7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d43d2f7 was d43d2f7, checked in by Jakub Jermar <jakub@…>, 20 years ago

Cleanup and fixes.

  • Property mode set to 100644
File size: 10.4 KB
Line 
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
42#define MAX_CMDLINE 256
43
44/** Simple kernel console.
45 *
46 * The console is realized by kernel thread kconsole.
47 * It doesn't understand any useful command on its own,
48 * but makes it possible for other kernel subsystems to
49 * register their own commands.
50 */
51
52/** Locking.
53 *
54 * There is a list of cmd_info_t structures. This list
55 * is protected by cmd_lock spinlock. Note that specially
56 * the link elements of cmd_info_t are protected by
57 * this lock.
58 *
59 * Each cmd_info_t also has its own lock, which protects
60 * all elements thereof except the link element.
61 *
62 * cmd_lock must be acquired before any cmd_info lock.
63 * When locking two cmd info structures, structure with
64 * lower address must be locked first.
65 */
66
67spinlock_t cmd_lock; /**< Lock protecting command list. */
68link_t cmd_head; /**< Command list. */
69
70static cmd_info_t *parse_cmdline(char *cmdline, size_t len);
71static bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end);
72
73/** Data and methods for 'help' command. */
74static int cmd_help(cmd_arg_t *argv);
75static cmd_info_t help_info;
76
77/** Data and methods for 'description' command. */
78static int cmd_desc(cmd_arg_t *argv);
79static void desc_help(void);
80static cmd_info_t desc_info;
81static char desc_buf[MAX_CMDLINE+1];
82static cmd_arg_t desc_argv = {
83 .type = ARG_TYPE_STRING,
84 .buffer = desc_buf,
85 .len = sizeof(desc_buf)
86};
87
88/** Data and methods for 'halt' command. */
89static int cmd_halt(cmd_arg_t *argv);
90static cmd_info_t halt_info;
91
92/** Initialize kconsole data structures. */
93void kconsole_init(void)
94{
95 spinlock_initialize(&cmd_lock);
96 list_initialize(&cmd_head);
97
98 help_info.name = "help";
99 help_info.description = "List supported commands.";
100 help_info.func = cmd_help;
101 help_info.help = NULL;
102 help_info.argc = 0;
103 help_info.argv = NULL;
104
105 spinlock_initialize(&help_info.lock);
106 link_initialize(&help_info.link);
107
108 if (!cmd_register(&help_info))
109 panic("could not register command %s\n", help_info.name);
110
111
112 desc_info.name = "describe";
113 desc_info.description = "Describe specified command.";
114 desc_info.help = desc_help;
115 desc_info.func = cmd_desc;
116 desc_info.argc = 1;
117 desc_info.argv = &desc_argv;
118
119 spinlock_initialize(&desc_info.lock);
120 link_initialize(&desc_info.link);
121
122 if (!cmd_register(&desc_info))
123 panic("could not register command %s\n", desc_info.name);
124
125
126 halt_info.name = "halt";
127 halt_info.description = "Halt the kernel.";
128 halt_info.func = cmd_halt;
129 halt_info.help = NULL;
130 halt_info.argc = 0;
131 halt_info.argv = NULL;
132
133 spinlock_initialize(&halt_info.lock);
134 link_initialize(&halt_info.link);
135
136 if (!cmd_register(&halt_info))
137 panic("could not register command %s\n", halt_info.name);
138}
139
140
141/** Register kconsole command.
142 *
143 * @param cmd Structure describing the command.
144 *
145 * @return 0 on failure, 1 on success.
146 */
147int cmd_register(cmd_info_t *cmd)
148{
149 ipl_t ipl;
150 link_t *cur;
151
152 ipl = interrupts_disable();
153 spinlock_lock(&cmd_lock);
154
155 /*
156 * Make sure the command is not already listed.
157 */
158 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
159 cmd_info_t *hlp;
160
161 hlp = list_get_instance(cur, cmd_info_t, link);
162
163 if (hlp == cmd) {
164 /* The command is already there. */
165 spinlock_unlock(&cmd_lock);
166 interrupts_restore(ipl);
167 return 0;
168 }
169
170 /* Avoid deadlock. */
171 if (hlp < cmd) {
172 spinlock_lock(&hlp->lock);
173 spinlock_lock(&cmd->lock);
174 } else {
175 spinlock_lock(&cmd->lock);
176 spinlock_lock(&hlp->lock);
177 }
178
179 if ((strncmp(hlp->name, cmd->name, strlen(cmd->name)) == 0)) {
180 /* The command is already there. */
181 spinlock_unlock(&hlp->lock);
182 spinlock_unlock(&cmd->lock);
183 spinlock_unlock(&cmd_lock);
184 interrupts_restore(ipl);
185 return 0;
186 }
187
188 spinlock_unlock(&hlp->lock);
189 spinlock_unlock(&cmd->lock);
190 }
191
192 /*
193 * Now the command can be added.
194 */
195 list_append(&cmd->link, &cmd_head);
196
197 spinlock_unlock(&cmd_lock);
198 interrupts_restore(ipl);
199 return 1;
200}
201
202/** Kernel console managing thread.
203 *
204 * @param arg Not used.
205 */
206void kconsole(void *arg)
207{
208 char cmdline[MAX_CMDLINE+1];
209 cmd_info_t *cmd_info;
210 count_t len;
211
212 if (!stdin) {
213 printf("%s: no stdin\n", __FUNCTION__);
214 return;
215 }
216
217 while (true) {
218 printf("%s> ", __FUNCTION__);
219 if (!(len = gets(stdin, cmdline, sizeof(cmdline))))
220 continue;
221 cmdline[len] = '\0';
222 cmd_info = parse_cmdline(cmdline, len);
223 if (!cmd_info)
224 continue;
225 (void) cmd_info->func(cmd_info->argv);
226 }
227}
228
229/** Parse command line.
230 *
231 * @param cmdline Command line as read from input device.
232 * @param len Command line length.
233 *
234 * @return Structure describing the command.
235 */
236cmd_info_t *parse_cmdline(char *cmdline, size_t len)
237{
238 index_t start = 0, end = 0;
239 cmd_info_t *cmd = NULL;
240 link_t *cur;
241 ipl_t ipl;
242 int i;
243
244 if (!parse_argument(cmdline, len, &start, &end)) {
245 /* Command line did not contain alphanumeric word. */
246 return NULL;
247 }
248
249 ipl = interrupts_disable();
250 spinlock_lock(&cmd_lock);
251
252 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
253 cmd_info_t *hlp;
254
255 hlp = list_get_instance(cur, cmd_info_t, link);
256 spinlock_lock(&hlp->lock);
257
258 if (strncmp(hlp->name, &cmdline[start], (end - start) + 1) == 0) {
259 cmd = hlp;
260 break;
261 }
262
263 spinlock_unlock(&hlp->lock);
264 }
265
266 spinlock_unlock(&cmd_lock);
267
268 if (!cmd) {
269 /* Unknown command. */
270 printf("Unknown command.\n");
271 interrupts_restore(ipl);
272 return NULL;
273 }
274
275 /* cmd == hlp is locked */
276
277 /*
278 * The command line must be further analyzed and
279 * the parameters therefrom must be matched and
280 * converted to those specified in the cmd info
281 * structure.
282 */
283
284 for (i = 0; i < cmd->argc; i++) {
285 char *buf;
286 start = end + 1;
287 if (!parse_argument(cmdline, len, &start, &end)) {
288 printf("Too few arguments.\n");
289 spinlock_unlock(&cmd->lock);
290 interrupts_restore(ipl);
291 return NULL;
292 }
293
294 switch (cmd->argv[i].type) {
295 case ARG_TYPE_STRING:
296 buf = cmd->argv[i].buffer;
297 strncpy(buf, (const char *) &cmdline[start], min((end - start) + 1, cmd->argv[i].len - 1));
298 buf[min((end - start) + 1, cmd->argv[i].len - 1)] = '\0';
299 break;
300 case ARG_TYPE_INT:
301 case ARG_TYPE_INVALID:
302 default:
303 panic("invalid argument type\n");
304 break;
305 }
306 }
307
308 start = end + 1;
309 if (parse_argument(cmdline, len, &start, &end)) {
310 printf("Too many arguments.\n");
311 spinlock_unlock(&cmd->lock);
312 interrupts_restore(ipl);
313 return NULL;
314 }
315
316 spinlock_unlock(&cmd->lock);
317 interrupts_restore(ipl);
318 return cmd;
319}
320
321/** Parse argument.
322 *
323 * Find start and end positions of command line argument.
324 *
325 * @param cmdline Command line as read from the input device.
326 * @param len Number of characters in cmdline.
327 * @param start On entry, 'start' contains pointer to the index
328 * of first unprocessed character of cmdline.
329 * On successful exit, it marks beginning of the next argument.
330 * @param end Undefined on entry. On exit, 'end' points to the last character
331 * of the next argument.
332 *
333 * @return false on failure, true on success.
334 */
335bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end)
336{
337 int i;
338 bool found_start = false;
339
340 ASSERT(start != NULL);
341 ASSERT(end != NULL);
342
343 for (i = *start; i < len; i++) {
344 if (!found_start) {
345 if (is_white(cmdline[i]))
346 (*start)++;
347 else
348 found_start = true;
349 } else {
350 if (is_white(cmdline[i]))
351 break;
352 }
353 }
354 *end = i - 1;
355
356 return found_start;
357}
358
359
360/** List supported commands.
361 *
362 * @param argv Argument vector.
363 *
364 * @return 0 on failure, 1 on success.
365 */
366int cmd_help(cmd_arg_t *argv)
367{
368 link_t *cur;
369 ipl_t ipl;
370
371 ipl = interrupts_disable();
372 spinlock_lock(&cmd_lock);
373
374 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
375 cmd_info_t *hlp;
376
377 hlp = list_get_instance(cur, cmd_info_t, link);
378 spinlock_lock(&hlp->lock);
379
380 printf("%s - %s\n", hlp->name, hlp->description);
381
382 spinlock_unlock(&hlp->lock);
383 }
384
385 spinlock_unlock(&cmd_lock);
386 interrupts_restore(ipl);
387
388 return 1;
389}
390
391/** Describe specified command.
392 *
393 * @param argv Argument vector.
394 *
395 * @return 0 on failure, 1 on success.
396 */
397int cmd_desc(cmd_arg_t *argv)
398{
399 link_t *cur;
400 ipl_t ipl;
401
402 ipl = interrupts_disable();
403 spinlock_lock(&cmd_lock);
404
405 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
406 cmd_info_t *hlp;
407
408 hlp = list_get_instance(cur, cmd_info_t, link);
409 spinlock_lock(&hlp->lock);
410
411 if (strncmp(hlp->name, (const char *) argv->buffer, strlen(hlp->name)) == 0) {
412 printf("%s - %s\n", hlp->name, hlp->description);
413 if (hlp->help)
414 hlp->help();
415 spinlock_unlock(&hlp->lock);
416 break;
417 }
418
419 spinlock_unlock(&hlp->lock);
420 }
421
422 spinlock_unlock(&cmd_lock);
423 interrupts_restore(ipl);
424
425 return 1;
426}
427
428/** Print detailed description of 'describe' command. */
429void desc_help(void)
430{
431 printf("Syntax: describe command_name\n");
432}
433
434/** Halt the kernel.
435 *
436 * @param argv Argument vector (ignored).
437 *
438 * @return 0 on failure, 1 on success (never returns).
439 */
440int cmd_halt(cmd_arg_t *argv)
441{
442 halt();
443 return 1;
444}
Note: See TracBrowser for help on using the repository browser.