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

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

enable kernel console output in case of kernel panic

  • the panic message might still be slightly unreadable due to the framebuffer driver optimizations (we don't waste time with full screen redraw), but at least you know that something bad happened and this issue can be tackled later
  • let's hope that enabling the kernel console cannot make things worse in the panicking kernel (especially with respect to the kernel/uspace interrupt handler priorities switch)
  • Property mode set to 100644
File size: 8.0 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>
41#include <arch/types.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>
[c583970]53#include <string.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;
[c0855a0]64/** First kernel log characters */
[98000fb]65static size_t klog_start = 0;
[c0855a0]66/** Number of valid kernel log characters */
[c859753]67static size_t klog_len = 0;
[c0855a0]68/** Number of stored (not printed) kernel log characters */
[c859753]69static size_t klog_stored = 0;
[c0855a0]70/** Number of stored kernel log characters for uspace */
[82b71ef1]71static size_t klog_uspace = 0;
72
[c0855a0]73/** Kernel log spinlock */
[a71c158]74SPINLOCK_STATIC_INITIALIZE_NAME(klog_lock, "*klog_lock");
[82b71ef1]75
76/** Physical memory area used for klog buffer */
77static parea_t klog_parea;
[516ff92]78
[b9c7425]79static indev_t stdin_sink;
80static outdev_t stdout_source;
81
[44b7783]82static indev_operations_t stdin_ops = {
83 .poll = NULL
84};
85
[b9c7425]86static void stdout_write(outdev_t *dev, wchar_t ch, bool silent);
[a71c158]87static void stdout_redraw(outdev_t *dev);
[b9c7425]88
89static outdev_operations_t stdout_ops = {
[a71c158]90 .write = stdout_write,
91 .redraw = stdout_redraw
[b9c7425]92};
93
[44b7783]94/** Silence output */
95bool silent = false;
96
[ac8e7a9]97/** Standard input and output character devices */
98indev_t *stdin = NULL;
99outdev_t *stdout = NULL;
[411b6a6]100
[44b7783]101indev_t *stdin_wire(void)
102{
103 if (stdin == NULL) {
[b9c7425]104 indev_initialize("stdin", &stdin_sink, &stdin_ops);
105 stdin = &stdin_sink;
[44b7783]106 }
107
108 return stdin;
109}
110
[b9c7425]111void stdout_wire(outdev_t *outdev)
112{
113 if (stdout == NULL) {
114 outdev_initialize("stdout", &stdout_source, &stdout_ops);
115 stdout = &stdout_source;
116 }
117
118 list_append(&outdev->link, &stdout->list);
119}
120
121static void stdout_write(outdev_t *dev, wchar_t ch, bool silent)
122{
123 link_t *cur;
124
125 for (cur = dev->list.next; cur != &dev->list; cur = cur->next) {
126 outdev_t *sink = list_get_instance(cur, outdev_t, link);
[a71c158]127 if ((sink) && (sink->op->write))
128 sink->op->write(sink, ch, silent);
129 }
130}
131
132static void stdout_redraw(outdev_t *dev)
133{
134 link_t *cur;
135
136 for (cur = dev->list.next; cur != &dev->list; cur = cur->next) {
137 outdev_t *sink = list_get_instance(cur, outdev_t, link);
138 if ((sink) && (sink->op->redraw))
139 sink->op->redraw(sink);
[b9c7425]140 }
141}
142
[82b71ef1]143/** Initialize kernel logging facility
144 *
145 * The shared area contains kernel cyclic buffer. Userspace application may
146 * be notified on new data with indication of position and size
147 * of the data within the circular buffer.
[ac8e7a9]148 *
[82b71ef1]149 */
150void klog_init(void)
151{
152 void *faddr = (void *) KA2PA(klog);
153
154 ASSERT((uintptr_t) faddr % FRAME_SIZE == 0);
155
156 klog_parea.pbase = (uintptr_t) faddr;
[eec616b]157 klog_parea.frames = SIZE2FRAMES(sizeof(klog));
[82b71ef1]158 ddi_parea_register(&klog_parea);
[ac8e7a9]159
[82b71ef1]160 sysinfo_set_item_val("klog.faddr", NULL, (unative_t) faddr);
[13a638d]161 sysinfo_set_item_val("klog.pages", NULL, KLOG_PAGES);
[ac8e7a9]162
[82b71ef1]163 spinlock_lock(&klog_lock);
164 klog_inited = true;
165 spinlock_unlock(&klog_lock);
166}
167
[516ff92]168void grab_console(void)
169{
[422fd81]170 bool prev = silent;
171
[516ff92]172 silent = false;
[a71c158]173 if ((stdout) && (stdout->op->redraw))
174 stdout->op->redraw(stdout);
[402de0c]175
176 /* Force the console to print the prompt */
[422fd81]177 if ((stdin) && (prev))
[402de0c]178 indev_push_character(stdin, '\n');
[516ff92]179}
180
181void release_console(void)
182{
[a71c158]183 // FIXME arch_release_console
[516ff92]184 silent = true;
185}
186
[312cc68]187/** Tell kernel to get keyboard/console access again */
188unative_t sys_debug_enable_console(void)
189{
190#ifdef CONFIG_KCONSOLE
191 grab_console();
192 return true;
193#else
194 return false;
195#endif
196}
197
198/** Tell kernel to relinquish keyboard/console access */
199unative_t sys_debug_disable_console(void)
200{
201 release_console();
202 return true;
203}
204
[ac8e7a9]205/** Get string from input character device.
[2677758]206 *
[ac8e7a9]207 * Read characters from input character device until first occurrence
[2677758]208 * of newline character.
209 *
[ac8e7a9]210 * @param indev Input character device.
[c583970]211 * @param buf Buffer where to store string terminated by NULL.
[abbc16e]212 * @param buflen Size of the buffer.
[ff3b3197]213 *
214 * @return Number of characters read.
[ac8e7a9]215 *
[2677758]216 */
[98000fb]217size_t gets(indev_t *indev, char *buf, size_t buflen)
[2677758]218{
[c583970]219 size_t offset = 0;
[98000fb]220 size_t count = 0;
[c583970]221 buf[offset] = 0;
[516ff92]222
[c583970]223 wchar_t ch;
[44b7783]224 while ((ch = indev_pop_character(indev)) != '\n') {
[e8a9dc3]225 if (ch == '\b') {
[c583970]226 if (count > 0) {
227 /* Space, backspace, space */
[e8a9dc3]228 putchar('\b');
229 putchar(' ');
230 putchar('\b');
[c583970]231
232 count--;
233 offset = str_lsize(buf, count);
234 buf[offset] = 0;
[e8a9dc3]235 }
[2677758]236 }
[c583970]237 if (chr_encode(ch, buf, &offset, buflen - 1) == EOK) {
238 putchar(ch);
239 count++;
240 buf[offset] = 0;
241 }
[2677758]242 }
[ac8e7a9]243
[c583970]244 return count;
[2677758]245}
246
[ac8e7a9]247/** Get character from input device & echo it to screen */
[c583970]248wchar_t getc(indev_t *indev)
[2677758]249{
[44b7783]250 wchar_t ch = indev_pop_character(indev);
[e8a9dc3]251 putchar(ch);
[2677758]252 return ch;
253}
[973be64e]254
[82b71ef1]255void klog_update(void)
256{
257 spinlock_lock(&klog_lock);
258
[18251cc]259 if ((klog_inited) && (event_is_subscribed(EVENT_KLOG)) && (klog_uspace > 0)) {
[05641a9e]260 event_notify_3(EVENT_KLOG, klog_start, klog_len, klog_uspace);
261 klog_uspace = 0;
262 }
[82b71ef1]263
264 spinlock_unlock(&klog_lock);
265}
266
[eec616b]267void putchar(const wchar_t ch)
[973be64e]268{
[82b71ef1]269 spinlock_lock(&klog_lock);
270
[ac8e7a9]271 if ((klog_stored > 0) && (stdout) && (stdout->op->write)) {
[c859753]272 /* Print charaters stored in kernel log */
[98000fb]273 size_t i;
[c859753]274 for (i = klog_len - klog_stored; i < klog_len; i++)
[171f9a1]275 stdout->op->write(stdout, klog[(klog_start + i) % KLOG_LENGTH], silent);
[c859753]276 klog_stored = 0;
277 }
278
279 /* Store character in the cyclic kernel log */
[171f9a1]280 klog[(klog_start + klog_len) % KLOG_LENGTH] = ch;
281 if (klog_len < KLOG_LENGTH)
[c859753]282 klog_len++;
283 else
[171f9a1]284 klog_start = (klog_start + 1) % KLOG_LENGTH;
[c859753]285
[ac8e7a9]286 if ((stdout) && (stdout->op->write))
[eec616b]287 stdout->op->write(stdout, ch, silent);
[c859753]288 else {
289 /* The character is just in the kernel log */
290 if (klog_stored < klog_len)
291 klog_stored++;
292 }
[82b71ef1]293
294 /* The character is stored for uspace */
295 if (klog_uspace < klog_len)
296 klog_uspace++;
297
[c05a50f]298 /* Check notify uspace to update */
299 bool update;
[eec616b]300 if ((klog_uspace > KLOG_LATENCY) || (ch == '\n'))
[c05a50f]301 update = true;
302 else
303 update = false;
304
[82b71ef1]305 spinlock_unlock(&klog_lock);
306
[c05a50f]307 if (update)
308 klog_update();
[973be64e]309}
[b45c443]310
[312cc68]311/** Print using kernel facility
312 *
313 * Print to kernel log.
314 *
315 */
[c583970]316unative_t sys_klog(int fd, const void *buf, size_t size)
[312cc68]317{
318 char *data;
319 int rc;
[eec616b]320
[c583970]321 if (size > PAGE_SIZE)
[9c70ed6]322 return (unative_t) ELIMIT;
[312cc68]323
[c583970]324 if (size > 0) {
325 data = (char *) malloc(size + 1, 0);
[312cc68]326 if (!data)
[9c70ed6]327 return (unative_t) ENOMEM;
[312cc68]328
[c583970]329 rc = copy_from_uspace(data, buf, size);
[312cc68]330 if (rc) {
331 free(data);
[9c70ed6]332 return (unative_t) rc;
[312cc68]333 }
[c583970]334 data[size] = 0;
[312cc68]335
336 printf("%s", data);
337 free(data);
338 } else
339 klog_update();
340
[c583970]341 return size;
[312cc68]342}
343
[06e1e95]344/** @}
[b45c443]345 */
Note: See TracBrowser for help on using the repository browser.