source: mainline/kernel/generic/src/console/console.c@ c9f5e238

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c9f5e238 was c9f5e238, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

devman in kconsole fixes

It seems better to launch devman later to prevent overflooding klog.

On real machine, the devman is way to quick and more pages are needed to
allow /app/klog read everything.

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/*
2 * Copyright (c) 2003 Josef Cejka
3 * Copyright (c) 2005 Jakub Jermar
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup genericconsole
31 * @{
32 */
33/** @file
34 */
35
36#include <console/console.h>
37#include <console/chardev.h>
38#include <sysinfo/sysinfo.h>
39#include <synch/waitq.h>
40#include <synch/spinlock.h>
41#include <typedefs.h>
42#include <ddi/irq.h>
43#include <ddi/ddi.h>
44#include <ipc/event.h>
45#include <ipc/irq.h>
46#include <arch.h>
47#include <panic.h>
48#include <print.h>
49#include <putchar.h>
50#include <atomic.h>
51#include <syscall/copy.h>
52#include <errno.h>
53#include <str.h>
54
55/*
56 * devman produces a lot of output and by giving so many pages
57 * we to allow /app/klog to catch-up.
58 */
59#ifdef CONFIG_DEVMAN_EARLY_LAUNCH
60#define KLOG_PAGES 64
61#else
62#define KLOG_PAGES 4
63#endif
64
65#define KLOG_LENGTH (KLOG_PAGES * PAGE_SIZE / sizeof(wchar_t))
66#define KLOG_LATENCY 8
67
68/** Kernel log cyclic buffer */
69static wchar_t klog[KLOG_LENGTH] __attribute__ ((aligned (PAGE_SIZE)));
70
71/** Kernel log initialized */
72static bool klog_inited = false;
73
74/** First kernel log characters */
75static size_t klog_start = 0;
76
77/** Number of valid kernel log characters */
78static size_t klog_len = 0;
79
80/** Number of stored (not printed) kernel log characters */
81static size_t klog_stored = 0;
82
83/** Number of stored kernel log characters for uspace */
84static size_t klog_uspace = 0;
85
86/** Kernel log spinlock */
87SPINLOCK_STATIC_INITIALIZE_NAME(klog_lock, "*klog_lock");
88
89/** Physical memory area used for klog buffer */
90static parea_t klog_parea;
91
92static indev_t stdin_sink;
93static outdev_t stdout_source;
94
95static indev_operations_t stdin_ops = {
96 .poll = NULL
97};
98
99static void stdout_write(outdev_t *, wchar_t, bool);
100static void stdout_redraw(outdev_t *);
101
102static outdev_operations_t stdout_ops = {
103 .write = stdout_write,
104 .redraw = stdout_redraw
105};
106
107/** Silence output */
108bool silent = false;
109
110/** Standard input and output character devices */
111indev_t *stdin = NULL;
112outdev_t *stdout = NULL;
113
114indev_t *stdin_wire(void)
115{
116 if (stdin == NULL) {
117 indev_initialize("stdin", &stdin_sink, &stdin_ops);
118 stdin = &stdin_sink;
119 }
120
121 return stdin;
122}
123
124void stdout_wire(outdev_t *outdev)
125{
126 if (stdout == NULL) {
127 outdev_initialize("stdout", &stdout_source, &stdout_ops);
128 stdout = &stdout_source;
129 }
130
131 list_append(&outdev->link, &stdout->list);
132}
133
134static void stdout_write(outdev_t *dev, wchar_t ch, bool silent)
135{
136 link_t *cur;
137
138 for (cur = dev->list.next; cur != &dev->list; cur = cur->next) {
139 outdev_t *sink = list_get_instance(cur, outdev_t, link);
140 if ((sink) && (sink->op->write))
141 sink->op->write(sink, ch, silent);
142 }
143}
144
145static void stdout_redraw(outdev_t *dev)
146{
147 link_t *cur;
148
149 for (cur = dev->list.next; cur != &dev->list; cur = cur->next) {
150 outdev_t *sink = list_get_instance(cur, outdev_t, link);
151 if ((sink) && (sink->op->redraw))
152 sink->op->redraw(sink);
153 }
154}
155
156/** Initialize kernel logging facility
157 *
158 * The shared area contains kernel cyclic buffer. Userspace application may
159 * be notified on new data with indication of position and size
160 * of the data within the circular buffer.
161 *
162 */
163void klog_init(void)
164{
165 void *faddr = (void *) KA2PA(klog);
166
167 ASSERT((uintptr_t) faddr % FRAME_SIZE == 0);
168
169 klog_parea.pbase = (uintptr_t) faddr;
170 klog_parea.frames = SIZE2FRAMES(sizeof(klog));
171 klog_parea.unpriv = false;
172 ddi_parea_register(&klog_parea);
173
174 sysinfo_set_item_val("klog.faddr", NULL, (sysarg_t) faddr);
175 sysinfo_set_item_val("klog.pages", NULL, KLOG_PAGES);
176
177 spinlock_lock(&klog_lock);
178 klog_inited = true;
179 spinlock_unlock(&klog_lock);
180}
181
182void grab_console(void)
183{
184 bool prev = silent;
185
186 silent = false;
187 if ((stdout) && (stdout->op->redraw))
188 stdout->op->redraw(stdout);
189
190 if ((stdin) && (prev)) {
191 /*
192 * Force the console to print the prompt.
193 */
194 indev_push_character(stdin, '\n');
195 }
196}
197
198void release_console(void)
199{
200 // FIXME arch_release_console
201 silent = true;
202}
203
204/** Tell kernel to get keyboard/console access again */
205sysarg_t sys_debug_enable_console(void)
206{
207#ifdef CONFIG_KCONSOLE
208 grab_console();
209 return true;
210#else
211 return false;
212#endif
213}
214
215/** Tell kernel to relinquish keyboard/console access */
216sysarg_t sys_debug_disable_console(void)
217{
218 release_console();
219 return true;
220}
221
222/** Get string from input character device.
223 *
224 * Read characters from input character device until first occurrence
225 * of newline character.
226 *
227 * @param indev Input character device.
228 * @param buf Buffer where to store string terminated by NULL.
229 * @param buflen Size of the buffer.
230 *
231 * @return Number of characters read.
232 *
233 */
234size_t gets(indev_t *indev, char *buf, size_t buflen)
235{
236 size_t offset = 0;
237 size_t count = 0;
238 buf[offset] = 0;
239
240 wchar_t ch;
241 while ((ch = indev_pop_character(indev)) != '\n') {
242 if (ch == '\b') {
243 if (count > 0) {
244 /* Space, backspace, space */
245 putchar('\b');
246 putchar(' ');
247 putchar('\b');
248
249 count--;
250 offset = str_lsize(buf, count);
251 buf[offset] = 0;
252 }
253 }
254 if (chr_encode(ch, buf, &offset, buflen - 1) == EOK) {
255 putchar(ch);
256 count++;
257 buf[offset] = 0;
258 }
259 }
260
261 return count;
262}
263
264/** Get character from input device & echo it to screen */
265wchar_t getc(indev_t *indev)
266{
267 wchar_t ch = indev_pop_character(indev);
268 putchar(ch);
269 return ch;
270}
271
272void klog_update(void)
273{
274 spinlock_lock(&klog_lock);
275
276 if ((klog_inited) && (event_is_subscribed(EVENT_KLOG)) && (klog_uspace > 0)) {
277 event_notify_3(EVENT_KLOG, klog_start, klog_len, klog_uspace);
278 klog_uspace = 0;
279 }
280
281 spinlock_unlock(&klog_lock);
282}
283
284void putchar(const wchar_t ch)
285{
286 spinlock_lock(&klog_lock);
287
288 if ((klog_stored > 0) && (stdout) && (stdout->op->write)) {
289 /* Print charaters stored in kernel log */
290 size_t i;
291 for (i = klog_len - klog_stored; i < klog_len; i++)
292 stdout->op->write(stdout, klog[(klog_start + i) % KLOG_LENGTH], silent);
293 klog_stored = 0;
294 }
295
296 /* Store character in the cyclic kernel log */
297 klog[(klog_start + klog_len) % KLOG_LENGTH] = ch;
298 if (klog_len < KLOG_LENGTH)
299 klog_len++;
300 else
301 klog_start = (klog_start + 1) % KLOG_LENGTH;
302
303 if ((stdout) && (stdout->op->write))
304 stdout->op->write(stdout, ch, silent);
305 else {
306 /*
307 * No standard output routine defined yet.
308 * The character is still stored in the kernel log
309 * for possible future output.
310 *
311 * The early_putchar() function is used to output
312 * the character for low-level debugging purposes.
313 * Note that the early_putc() function might be
314 * a no-op on certain hardware configurations.
315 *
316 */
317 early_putchar(ch);
318
319 if (klog_stored < klog_len)
320 klog_stored++;
321 }
322
323 /* The character is stored for uspace */
324 if (klog_uspace < klog_len)
325 klog_uspace++;
326
327 /* Check notify uspace to update */
328 bool update;
329 if ((klog_uspace > KLOG_LATENCY) || (ch == '\n'))
330 update = true;
331 else
332 update = false;
333
334 spinlock_unlock(&klog_lock);
335
336 if (update)
337 klog_update();
338}
339
340/** Print using kernel facility
341 *
342 * Print to kernel log.
343 *
344 */
345sysarg_t sys_klog(int fd, const void *buf, size_t size)
346{
347 char *data;
348 int rc;
349
350 if (size > PAGE_SIZE)
351 return (sysarg_t) ELIMIT;
352
353 if (size > 0) {
354 data = (char *) malloc(size + 1, 0);
355 if (!data)
356 return (sysarg_t) ENOMEM;
357
358 rc = copy_from_uspace(data, buf, size);
359 if (rc) {
360 free(data);
361 return (sysarg_t) rc;
362 }
363 data[size] = 0;
364
365 printf("%s", data);
366 free(data);
367 } else
368 klog_update();
369
370 return size;
371}
372
373/** @}
374 */
Note: See TracBrowser for help on using the repository browser.