Subversion Repositories HelenOS-historic

Rev

Rev 512 | Rev 518 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
510 jermar 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>
517 jermar 33
#include <panic.h>
510 jermar 34
#include <typedefs.h>
35
#include <arch/types.h>
517 jermar 36
#include <list.h>
37
#include <arch.h>
38
#include <func.h>
39
#include <macros.h>
510 jermar 40
 
517 jermar 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
 
510 jermar 155
/** Kernel console managing thread.
156
 *
157
 * @param arg Not used.
158
 */
159
void kconsole(void *arg)
160
{
517 jermar 161
	char cmdline[MAX_CMDLINE+1];
162
	cmd_info_t *cmd_info;
163
	count_t len;
510 jermar 164
 
165
	if (!stdin) {
166
		printf("%s: no stdin\n", __FUNCTION__);
167
		return;
168
	}
169
 
170
	while (true) {
171
		printf("%s> ", __FUNCTION__);
517 jermar 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);
510 jermar 180
	}
181
}
517 jermar 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
}