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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since da52547 was da52547, checked in by Martin Decky <martin@…>, 15 years ago

add early_putchar() which can be used to do early kernel console output for debugging purposes
(the availability of this feature depends on each platform and specific configuration, currently it works only on ia32/amd64 with EGA and no framebuffer)
instrument more kernel functions
mark some functions as no_instrument (context_restore(), overlaps(), main_bsp())

  • Property mode set to 100644
File size: 8.3 KB
RevLine 
[2677758]1/*
[df4ed85]2 * Copyright (c) 2003 Josef Cejka
3 * Copyright (c) 2005 Jakub Jermar
[2677758]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
[06e1e95]30/** @addtogroup genericconsole
[b45c443]31 * @{
32 */
33/** @file
34 */
35
[2677758]36#include <console/console.h>
37#include <console/chardev.h>
[82b71ef1]38#include <sysinfo/sysinfo.h>
[2677758]39#include <synch/waitq.h>
40#include <synch/spinlock.h>
[d99c1d2]41#include <typedefs.h>
[82b71ef1]42#include <ddi/irq.h>
43#include <ddi/ddi.h>
[13a638d]44#include <ipc/event.h>
[82b71ef1]45#include <ipc/irq.h>
[2677758]46#include <arch.h>
[b8da2a3]47#include <panic.h>
[93b84b3]48#include <print.h>
[eec616b]49#include <putchar.h>
[23684b7]50#include <atomic.h>
[312cc68]51#include <syscall/copy.h>
52#include <errno.h>
[19f857a]53#include <str.h>
[2677758]54
[13a638d]55#define KLOG_PAGES 4
56#define KLOG_LENGTH (KLOG_PAGES * PAGE_SIZE / sizeof(wchar_t))
[eec616b]57#define KLOG_LATENCY 8
[c859753]58
[c0855a0]59/** Kernel log cyclic buffer */
[171f9a1]60static wchar_t klog[KLOG_LENGTH] __attribute__ ((aligned (PAGE_SIZE)));
[c859753]61
[c0855a0]62/** Kernel log initialized */
[82b71ef1]63static bool klog_inited = false;
[da1bafb]64
[c0855a0]65/** First kernel log characters */
[98000fb]66static size_t klog_start = 0;
[da1bafb]67
[c0855a0]68/** Number of valid kernel log characters */
[c859753]69static size_t klog_len = 0;
[da1bafb]70
[c0855a0]71/** Number of stored (not printed) kernel log characters */
[c859753]72static size_t klog_stored = 0;
[da1bafb]73
[c0855a0]74/** Number of stored kernel log characters for uspace */
[82b71ef1]75static size_t klog_uspace = 0;
76
[c0855a0]77/** Kernel log spinlock */
[a71c158]78SPINLOCK_STATIC_INITIALIZE_NAME(klog_lock, "*klog_lock");
[82b71ef1]79
80/** Physical memory area used for klog buffer */
81static parea_t klog_parea;
[516ff92]82
[b9c7425]83static indev_t stdin_sink;
84static outdev_t stdout_source;
85
[44b7783]86static indev_operations_t stdin_ops = {
87 .poll = NULL
88};
89
[da1bafb]90static void stdout_write(outdev_t *, wchar_t, bool);
91static void stdout_redraw(outdev_t *);
[b9c7425]92
93static outdev_operations_t stdout_ops = {
[a71c158]94 .write = stdout_write,
95 .redraw = stdout_redraw
[b9c7425]96};
97
[44b7783]98/** Silence output */
99bool silent = false;
100
[ac8e7a9]101/** Standard input and output character devices */
102indev_t *stdin = NULL;
103outdev_t *stdout = NULL;
[411b6a6]104
[44b7783]105indev_t *stdin_wire(void)
106{
107 if (stdin == NULL) {
[b9c7425]108 indev_initialize("stdin", &stdin_sink, &stdin_ops);
109 stdin = &stdin_sink;
[44b7783]110 }
111
112 return stdin;
113}
114
[b9c7425]115void stdout_wire(outdev_t *outdev)
116{
117 if (stdout == NULL) {
118 outdev_initialize("stdout", &stdout_source, &stdout_ops);
119 stdout = &stdout_source;
120 }
121
122 list_append(&outdev->link, &stdout->list);
123}
124
125static void stdout_write(outdev_t *dev, wchar_t ch, bool silent)
126{
127 link_t *cur;
128
129 for (cur = dev->list.next; cur != &dev->list; cur = cur->next) {
130 outdev_t *sink = list_get_instance(cur, outdev_t, link);
[a71c158]131 if ((sink) && (sink->op->write))
132 sink->op->write(sink, ch, silent);
133 }
134}
135
136static void stdout_redraw(outdev_t *dev)
137{
138 link_t *cur;
139
140 for (cur = dev->list.next; cur != &dev->list; cur = cur->next) {
141 outdev_t *sink = list_get_instance(cur, outdev_t, link);
142 if ((sink) && (sink->op->redraw))
143 sink->op->redraw(sink);
[b9c7425]144 }
145}
146
[82b71ef1]147/** Initialize kernel logging facility
148 *
149 * The shared area contains kernel cyclic buffer. Userspace application may
150 * be notified on new data with indication of position and size
151 * of the data within the circular buffer.
[ac8e7a9]152 *
[82b71ef1]153 */
154void klog_init(void)
155{
156 void *faddr = (void *) KA2PA(klog);
157
158 ASSERT((uintptr_t) faddr % FRAME_SIZE == 0);
159
160 klog_parea.pbase = (uintptr_t) faddr;
[eec616b]161 klog_parea.frames = SIZE2FRAMES(sizeof(klog));
[82b71ef1]162 ddi_parea_register(&klog_parea);
[ac8e7a9]163
[82b71ef1]164 sysinfo_set_item_val("klog.faddr", NULL, (unative_t) faddr);
[13a638d]165 sysinfo_set_item_val("klog.pages", NULL, KLOG_PAGES);
[ac8e7a9]166
[82b71ef1]167 spinlock_lock(&klog_lock);
168 klog_inited = true;
169 spinlock_unlock(&klog_lock);
170}
171
[516ff92]172void grab_console(void)
173{
[422fd81]174 bool prev = silent;
175
[516ff92]176 silent = false;
[a71c158]177 if ((stdout) && (stdout->op->redraw))
178 stdout->op->redraw(stdout);
[402de0c]179
[da1bafb]180 if ((stdin) && (prev)) {
181 /*
182 * Force the console to print the prompt.
183 */
[402de0c]184 indev_push_character(stdin, '\n');
[da1bafb]185 }
[516ff92]186}
187
188void release_console(void)
189{
[a71c158]190 // FIXME arch_release_console
[516ff92]191 silent = true;
192}
193
[312cc68]194/** Tell kernel to get keyboard/console access again */
195unative_t sys_debug_enable_console(void)
196{
197#ifdef CONFIG_KCONSOLE
198 grab_console();
199 return true;
200#else
201 return false;
202#endif
203}
204
205/** Tell kernel to relinquish keyboard/console access */
206unative_t sys_debug_disable_console(void)
207{
208 release_console();
209 return true;
210}
211
[ac8e7a9]212/** Get string from input character device.
[2677758]213 *
[ac8e7a9]214 * Read characters from input character device until first occurrence
[2677758]215 * of newline character.
216 *
[ac8e7a9]217 * @param indev Input character device.
[c583970]218 * @param buf Buffer where to store string terminated by NULL.
[abbc16e]219 * @param buflen Size of the buffer.
[ff3b3197]220 *
221 * @return Number of characters read.
[ac8e7a9]222 *
[2677758]223 */
[98000fb]224size_t gets(indev_t *indev, char *buf, size_t buflen)
[2677758]225{
[c583970]226 size_t offset = 0;
[98000fb]227 size_t count = 0;
[c583970]228 buf[offset] = 0;
[516ff92]229
[c583970]230 wchar_t ch;
[44b7783]231 while ((ch = indev_pop_character(indev)) != '\n') {
[e8a9dc3]232 if (ch == '\b') {
[c583970]233 if (count > 0) {
234 /* Space, backspace, space */
[e8a9dc3]235 putchar('\b');
236 putchar(' ');
237 putchar('\b');
[c583970]238
239 count--;
240 offset = str_lsize(buf, count);
241 buf[offset] = 0;
[e8a9dc3]242 }
[2677758]243 }
[c583970]244 if (chr_encode(ch, buf, &offset, buflen - 1) == EOK) {
245 putchar(ch);
246 count++;
247 buf[offset] = 0;
248 }
[2677758]249 }
[ac8e7a9]250
[c583970]251 return count;
[2677758]252}
253
[ac8e7a9]254/** Get character from input device & echo it to screen */
[c583970]255wchar_t getc(indev_t *indev)
[2677758]256{
[44b7783]257 wchar_t ch = indev_pop_character(indev);
[e8a9dc3]258 putchar(ch);
[2677758]259 return ch;
260}
[973be64e]261
[82b71ef1]262void klog_update(void)
263{
264 spinlock_lock(&klog_lock);
265
[18251cc]266 if ((klog_inited) && (event_is_subscribed(EVENT_KLOG)) && (klog_uspace > 0)) {
[05641a9e]267 event_notify_3(EVENT_KLOG, klog_start, klog_len, klog_uspace);
268 klog_uspace = 0;
269 }
[82b71ef1]270
271 spinlock_unlock(&klog_lock);
272}
273
[eec616b]274void putchar(const wchar_t ch)
[973be64e]275{
[82b71ef1]276 spinlock_lock(&klog_lock);
277
[ac8e7a9]278 if ((klog_stored > 0) && (stdout) && (stdout->op->write)) {
[c859753]279 /* Print charaters stored in kernel log */
[98000fb]280 size_t i;
[c859753]281 for (i = klog_len - klog_stored; i < klog_len; i++)
[171f9a1]282 stdout->op->write(stdout, klog[(klog_start + i) % KLOG_LENGTH], silent);
[c859753]283 klog_stored = 0;
284 }
285
286 /* Store character in the cyclic kernel log */
[171f9a1]287 klog[(klog_start + klog_len) % KLOG_LENGTH] = ch;
288 if (klog_len < KLOG_LENGTH)
[c859753]289 klog_len++;
290 else
[171f9a1]291 klog_start = (klog_start + 1) % KLOG_LENGTH;
[c859753]292
[ac8e7a9]293 if ((stdout) && (stdout->op->write))
[eec616b]294 stdout->op->write(stdout, ch, silent);
[c859753]295 else {
[da52547]296 /*
297 * No standard output routine defined yet.
298 * The character is still stored in the kernel log
299 * for possible future output.
300 *
301 * The early_putchar() function is used to output
302 * the character for low-level debugging purposes.
303 * Note that the early_putc() function might be
304 * a no-op on certain hardware configurations.
305 *
306 */
307 early_putchar(ch);
308
[c859753]309 if (klog_stored < klog_len)
310 klog_stored++;
311 }
[82b71ef1]312
313 /* The character is stored for uspace */
314 if (klog_uspace < klog_len)
315 klog_uspace++;
316
[c05a50f]317 /* Check notify uspace to update */
318 bool update;
[eec616b]319 if ((klog_uspace > KLOG_LATENCY) || (ch == '\n'))
[c05a50f]320 update = true;
321 else
322 update = false;
323
[82b71ef1]324 spinlock_unlock(&klog_lock);
325
[c05a50f]326 if (update)
327 klog_update();
[973be64e]328}
[b45c443]329
[312cc68]330/** Print using kernel facility
331 *
332 * Print to kernel log.
333 *
334 */
[c583970]335unative_t sys_klog(int fd, const void *buf, size_t size)
[312cc68]336{
337 char *data;
338 int rc;
[eec616b]339
[c583970]340 if (size > PAGE_SIZE)
[9c70ed6]341 return (unative_t) ELIMIT;
[312cc68]342
[c583970]343 if (size > 0) {
344 data = (char *) malloc(size + 1, 0);
[312cc68]345 if (!data)
[9c70ed6]346 return (unative_t) ENOMEM;
[312cc68]347
[c583970]348 rc = copy_from_uspace(data, buf, size);
[312cc68]349 if (rc) {
350 free(data);
[9c70ed6]351 return (unative_t) rc;
[312cc68]352 }
[c583970]353 data[size] = 0;
[312cc68]354
355 printf("%s", data);
356 free(data);
357 } else
358 klog_update();
359
[c583970]360 return size;
[312cc68]361}
362
[06e1e95]363/** @}
[b45c443]364 */
Note: See TracBrowser for help on using the repository browser.