source: mainline/generic/src/console/kconsole.c@ 402fc8bf

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 402fc8bf was 402fc8bf, checked in by Ondrej Palkovsky <ondrap@…>, 20 years ago

Removed unnecessary interrupts_disable from kconsole.
Fixed calling gets() with interrupts_disable.

  • Property mode set to 100644
File size: 10.1 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, "kconsole_cmd");
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, "kconsole_help");
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, "kconsole_desc");
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, "kconsole_halt");
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 spinlock_lock(&cmd_lock);
153
154 /*
155 * Make sure the command is not already listed.
156 */
157 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
158 cmd_info_t *hlp;
159
160 hlp = list_get_instance(cur, cmd_info_t, link);
161
162 if (hlp == cmd) {
163 /* The command is already there. */
164 spinlock_unlock(&cmd_lock);
165 return 0;
166 }
167
168 /* Avoid deadlock. */
169 if (hlp < cmd) {
170 spinlock_lock(&hlp->lock);
171 spinlock_lock(&cmd->lock);
172 } else {
173 spinlock_lock(&cmd->lock);
174 spinlock_lock(&hlp->lock);
175 }
176
177 if ((strncmp(hlp->name, cmd->name, strlen(cmd->name)) == 0)) {
178 /* The command is already there. */
179 spinlock_unlock(&hlp->lock);
180 spinlock_unlock(&cmd->lock);
181 spinlock_unlock(&cmd_lock);
182 return 0;
183 }
184
185 spinlock_unlock(&hlp->lock);
186 spinlock_unlock(&cmd->lock);
187 }
188
189 /*
190 * Now the command can be added.
191 */
192 list_append(&cmd->link, &cmd_head);
193
194 spinlock_unlock(&cmd_lock);
195 return 1;
196}
197
198/** Kernel console managing thread.
199 *
200 * @param arg Not used.
201 */
202void kconsole(void *arg)
203{
204 char cmdline[MAX_CMDLINE+1];
205 cmd_info_t *cmd_info;
206 count_t len;
207
208 if (!stdin) {
209 printf("%s: no stdin\n", __FUNCTION__);
210 return;
211 }
212
213 while (true) {
214 printf("%s> ", __FUNCTION__);
215 if (!(len = gets(stdin, cmdline, sizeof(cmdline))))
216 continue;
217 cmdline[len] = '\0';
218 cmd_info = parse_cmdline(cmdline, len);
219 if (!cmd_info)
220 continue;
221 (void) cmd_info->func(cmd_info->argv);
222 }
223}
224
225/** Parse command line.
226 *
227 * @param cmdline Command line as read from input device.
228 * @param len Command line length.
229 *
230 * @return Structure describing the command.
231 */
232cmd_info_t *parse_cmdline(char *cmdline, size_t len)
233{
234 index_t start = 0, end = 0;
235 cmd_info_t *cmd = NULL;
236 link_t *cur;
237 ipl_t ipl;
238 int i;
239
240 if (!parse_argument(cmdline, len, &start, &end)) {
241 /* Command line did not contain alphanumeric word. */
242 return NULL;
243 }
244
245 spinlock_lock(&cmd_lock);
246
247 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
248 cmd_info_t *hlp;
249
250 hlp = list_get_instance(cur, cmd_info_t, link);
251 spinlock_lock(&hlp->lock);
252
253 if (strncmp(hlp->name, &cmdline[start], (end - start) + 1) == 0) {
254 cmd = hlp;
255 break;
256 }
257
258 spinlock_unlock(&hlp->lock);
259 }
260
261 spinlock_unlock(&cmd_lock);
262
263 if (!cmd) {
264 /* Unknown command. */
265 printf("Unknown command.\n");
266 return NULL;
267 }
268
269 /* cmd == hlp is locked */
270
271 /*
272 * The command line must be further analyzed and
273 * the parameters therefrom must be matched and
274 * converted to those specified in the cmd info
275 * structure.
276 */
277
278 for (i = 0; i < cmd->argc; i++) {
279 char *buf;
280 start = end + 1;
281 if (!parse_argument(cmdline, len, &start, &end)) {
282 printf("Too few arguments.\n");
283 spinlock_unlock(&cmd->lock);
284 return NULL;
285 }
286
287 switch (cmd->argv[i].type) {
288 case ARG_TYPE_STRING:
289 buf = cmd->argv[i].buffer;
290 strncpy(buf, (const char *) &cmdline[start], min((end - start) + 1, cmd->argv[i].len - 1));
291 buf[min((end - start) + 1, cmd->argv[i].len - 1)] = '\0';
292 break;
293 case ARG_TYPE_INT:
294 case ARG_TYPE_INVALID:
295 default:
296 panic("invalid argument type\n");
297 break;
298 }
299 }
300
301 start = end + 1;
302 if (parse_argument(cmdline, len, &start, &end)) {
303 printf("Too many arguments.\n");
304 spinlock_unlock(&cmd->lock);
305 return NULL;
306 }
307
308 spinlock_unlock(&cmd->lock);
309 return cmd;
310}
311
312/** Parse argument.
313 *
314 * Find start and end positions of command line argument.
315 *
316 * @param cmdline Command line as read from the input device.
317 * @param len Number of characters in cmdline.
318 * @param start On entry, 'start' contains pointer to the index
319 * of first unprocessed character of cmdline.
320 * On successful exit, it marks beginning of the next argument.
321 * @param end Undefined on entry. On exit, 'end' points to the last character
322 * of the next argument.
323 *
324 * @return false on failure, true on success.
325 */
326bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end)
327{
328 int i;
329 bool found_start = false;
330
331 ASSERT(start != NULL);
332 ASSERT(end != NULL);
333
334 for (i = *start; i < len; i++) {
335 if (!found_start) {
336 if (is_white(cmdline[i]))
337 (*start)++;
338 else
339 found_start = true;
340 } else {
341 if (is_white(cmdline[i]))
342 break;
343 }
344 }
345 *end = i - 1;
346
347 return found_start;
348}
349
350
351/** List supported commands.
352 *
353 * @param argv Argument vector.
354 *
355 * @return 0 on failure, 1 on success.
356 */
357int cmd_help(cmd_arg_t *argv)
358{
359 link_t *cur;
360 ipl_t ipl;
361
362 spinlock_lock(&cmd_lock);
363
364 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
365 cmd_info_t *hlp;
366
367 hlp = list_get_instance(cur, cmd_info_t, link);
368 spinlock_lock(&hlp->lock);
369
370 printf("%s - %s\n", hlp->name, hlp->description);
371
372 spinlock_unlock(&hlp->lock);
373 }
374
375 spinlock_unlock(&cmd_lock);
376
377 return 1;
378}
379
380/** Describe specified command.
381 *
382 * @param argv Argument vector.
383 *
384 * @return 0 on failure, 1 on success.
385 */
386int cmd_desc(cmd_arg_t *argv)
387{
388 link_t *cur;
389 ipl_t ipl;
390
391 spinlock_lock(&cmd_lock);
392
393 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
394 cmd_info_t *hlp;
395
396 hlp = list_get_instance(cur, cmd_info_t, link);
397 spinlock_lock(&hlp->lock);
398
399 if (strncmp(hlp->name, (const char *) argv->buffer, strlen(hlp->name)) == 0) {
400 printf("%s - %s\n", hlp->name, hlp->description);
401 if (hlp->help)
402 hlp->help();
403 spinlock_unlock(&hlp->lock);
404 break;
405 }
406
407 spinlock_unlock(&hlp->lock);
408 }
409
410 spinlock_unlock(&cmd_lock);
411
412 return 1;
413}
414
415/** Print detailed description of 'describe' command. */
416void desc_help(void)
417{
418 printf("Syntax: describe command_name\n");
419}
420
421/** Halt the kernel.
422 *
423 * @param argv Argument vector (ignored).
424 *
425 * @return 0 on failure, 1 on success (never returns).
426 */
427int cmd_halt(cmd_arg_t *argv)
428{
429 halt();
430 return 1;
431}
Note: See TracBrowser for help on using the repository browser.