source: mainline/kernel/generic/src/console/console.c@ 48bcf49

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 48bcf49 was 63e27ef, checked in by Jiri Svoboda <jiri@…>, 8 years ago

ASSERT → assert

  • Property mode set to 100644
File size: 9.7 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
[63e27ef]36#include <assert.h>
[2677758]37#include <console/console.h>
38#include <console/chardev.h>
[82b71ef1]39#include <sysinfo/sysinfo.h>
[2677758]40#include <synch/waitq.h>
41#include <synch/spinlock.h>
[d99c1d2]42#include <typedefs.h>
[82b71ef1]43#include <ddi/irq.h>
44#include <ddi/ddi.h>
[13a638d]45#include <ipc/event.h>
[82b71ef1]46#include <ipc/irq.h>
[2677758]47#include <arch.h>
[b8da2a3]48#include <panic.h>
[93b84b3]49#include <print.h>
[eec616b]50#include <putchar.h>
[23684b7]51#include <atomic.h>
[312cc68]52#include <syscall/copy.h>
53#include <errno.h>
[19f857a]54#include <str.h>
[6fa9a99d]55#include <abi/kio.h>
[1066041]56#include <mm/frame.h> /* SIZE2FRAMES */
57#include <mm/slab.h> /* malloc */
[2677758]58
[6fa9a99d]59#define KIO_PAGES 8
60#define KIO_LENGTH (KIO_PAGES * PAGE_SIZE / sizeof(wchar_t))
[c859753]61
[c0855a0]62/** Kernel log cyclic buffer */
[6fa9a99d]63wchar_t kio[KIO_LENGTH] __attribute__((aligned(PAGE_SIZE)));
[c859753]64
[c0855a0]65/** Kernel log initialized */
[6fa9a99d]66static atomic_t kio_inited = {false};
[da1bafb]67
[c0855a0]68/** First kernel log characters */
[6fa9a99d]69static size_t kio_start = 0;
[da1bafb]70
[c0855a0]71/** Number of valid kernel log characters */
[6fa9a99d]72static size_t kio_len = 0;
[da1bafb]73
[c0855a0]74/** Number of stored (not printed) kernel log characters */
[6fa9a99d]75static size_t kio_stored = 0;
[da1bafb]76
[c0855a0]77/** Number of stored kernel log characters for uspace */
[6fa9a99d]78static size_t kio_uspace = 0;
[82b71ef1]79
[c0855a0]80/** Kernel log spinlock */
[91db0280]81SPINLOCK_INITIALIZE_NAME(kio_lock, "kio_lock");
[82b71ef1]82
[6fa9a99d]83/** Physical memory area used for kio buffer */
84static parea_t kio_parea;
[516ff92]85
[b9c7425]86static indev_t stdin_sink;
87static outdev_t stdout_source;
88
[7ddc2c7]89static void stdin_signal(indev_t *, indev_signal_t);
90
[44b7783]91static indev_operations_t stdin_ops = {
[7ddc2c7]92 .poll = NULL,
93 .signal = stdin_signal
[44b7783]94};
95
[b366a6f4]96static void stdout_write(outdev_t *, wchar_t);
[da1bafb]97static void stdout_redraw(outdev_t *);
[7ddc2c7]98static void stdout_scroll_up(outdev_t *);
99static void stdout_scroll_down(outdev_t *);
[b9c7425]100
101static outdev_operations_t stdout_ops = {
[a71c158]102 .write = stdout_write,
[7ddc2c7]103 .redraw = stdout_redraw,
104 .scroll_up = stdout_scroll_up,
105 .scroll_down = stdout_scroll_down
[b9c7425]106};
107
[b366a6f4]108/** Override kernel console lockout */
109bool console_override = false;
[44b7783]110
[ac8e7a9]111/** Standard input and output character devices */
112indev_t *stdin = NULL;
113outdev_t *stdout = NULL;
[411b6a6]114
[44b7783]115indev_t *stdin_wire(void)
116{
117 if (stdin == NULL) {
[b9c7425]118 indev_initialize("stdin", &stdin_sink, &stdin_ops);
119 stdin = &stdin_sink;
[44b7783]120 }
121
122 return stdin;
123}
124
[7ddc2c7]125static void stdin_signal(indev_t *indev, indev_signal_t signal)
126{
127 switch (signal) {
128 case INDEV_SIGNAL_SCROLL_UP:
129 if (stdout != NULL)
130 stdout_scroll_up(stdout);
131 break;
132 case INDEV_SIGNAL_SCROLL_DOWN:
133 if (stdout != NULL)
134 stdout_scroll_down(stdout);
135 break;
136 }
137}
138
[b9c7425]139void stdout_wire(outdev_t *outdev)
140{
141 if (stdout == NULL) {
142 outdev_initialize("stdout", &stdout_source, &stdout_ops);
143 stdout = &stdout_source;
144 }
145
146 list_append(&outdev->link, &stdout->list);
147}
148
[b366a6f4]149static void stdout_write(outdev_t *dev, wchar_t ch)
[b9c7425]150{
[feeac0d]151 list_foreach(dev->list, link, outdev_t, sink) {
[a71c158]152 if ((sink) && (sink->op->write))
[b366a6f4]153 sink->op->write(sink, ch);
[a71c158]154 }
155}
156
157static void stdout_redraw(outdev_t *dev)
158{
[feeac0d]159 list_foreach(dev->list, link, outdev_t, sink) {
[a71c158]160 if ((sink) && (sink->op->redraw))
161 sink->op->redraw(sink);
[b9c7425]162 }
163}
164
[7ddc2c7]165static void stdout_scroll_up(outdev_t *dev)
166{
167 list_foreach(dev->list, link, outdev_t, sink) {
168 if ((sink) && (sink->op->scroll_up))
169 sink->op->scroll_up(sink);
170 }
171}
172
173static void stdout_scroll_down(outdev_t *dev)
174{
175 list_foreach(dev->list, link, outdev_t, sink) {
176 if ((sink) && (sink->op->scroll_down))
177 sink->op->scroll_down(sink);
178 }
179}
180
[82b71ef1]181/** Initialize kernel logging facility
182 *
183 * The shared area contains kernel cyclic buffer. Userspace application may
184 * be notified on new data with indication of position and size
185 * of the data within the circular buffer.
[ac8e7a9]186 *
[82b71ef1]187 */
[6fa9a99d]188void kio_init(void)
[82b71ef1]189{
[6fa9a99d]190 void *faddr = (void *) KA2PA(kio);
[82b71ef1]191
[63e27ef]192 assert((uintptr_t) faddr % FRAME_SIZE == 0);
[82b71ef1]193
[6fa9a99d]194 kio_parea.pbase = (uintptr_t) faddr;
195 kio_parea.frames = SIZE2FRAMES(sizeof(kio));
196 kio_parea.unpriv = false;
197 kio_parea.mapped = false;
198 ddi_parea_register(&kio_parea);
[ac8e7a9]199
[6fa9a99d]200 sysinfo_set_item_val("kio.faddr", NULL, (sysarg_t) faddr);
201 sysinfo_set_item_val("kio.pages", NULL, KIO_PAGES);
[97d42d5]202
[6fa9a99d]203 event_set_unmask_callback(EVENT_KIO, kio_update);
204 atomic_set(&kio_inited, true);
[82b71ef1]205}
206
[516ff92]207void grab_console(void)
208{
[593e023]209 event_notify_1(EVENT_KCONSOLE, false, true);
[b366a6f4]210 bool prev = console_override;
[422fd81]211
[b366a6f4]212 console_override = true;
[a71c158]213 if ((stdout) && (stdout->op->redraw))
214 stdout->op->redraw(stdout);
[402de0c]215
[b366a6f4]216 if ((stdin) && (!prev)) {
[da1bafb]217 /*
218 * Force the console to print the prompt.
219 */
[402de0c]220 indev_push_character(stdin, '\n');
[da1bafb]221 }
[516ff92]222}
223
224void release_console(void)
225{
[b366a6f4]226 console_override = false;
[593e023]227 event_notify_1(EVENT_KCONSOLE, false, false);
[516ff92]228}
229
[b366a6f4]230/** Activate kernel console override */
[f6ab787]231sysarg_t sys_debug_console(void)
[312cc68]232{
233#ifdef CONFIG_KCONSOLE
234 grab_console();
235 return true;
236#else
237 return false;
238#endif
239}
240
[ac8e7a9]241/** Get string from input character device.
[2677758]242 *
[ac8e7a9]243 * Read characters from input character device until first occurrence
[2677758]244 * of newline character.
245 *
[ac8e7a9]246 * @param indev Input character device.
[c583970]247 * @param buf Buffer where to store string terminated by NULL.
[abbc16e]248 * @param buflen Size of the buffer.
[ff3b3197]249 *
250 * @return Number of characters read.
[ac8e7a9]251 *
[2677758]252 */
[98000fb]253size_t gets(indev_t *indev, char *buf, size_t buflen)
[2677758]254{
[c583970]255 size_t offset = 0;
[98000fb]256 size_t count = 0;
[c583970]257 buf[offset] = 0;
[516ff92]258
[c583970]259 wchar_t ch;
[44b7783]260 while ((ch = indev_pop_character(indev)) != '\n') {
[e8a9dc3]261 if (ch == '\b') {
[c583970]262 if (count > 0) {
263 /* Space, backspace, space */
[e8a9dc3]264 putchar('\b');
265 putchar(' ');
266 putchar('\b');
[c583970]267
268 count--;
269 offset = str_lsize(buf, count);
270 buf[offset] = 0;
[e8a9dc3]271 }
[2677758]272 }
[7ddc2c7]273
[c583970]274 if (chr_encode(ch, buf, &offset, buflen - 1) == EOK) {
275 putchar(ch);
276 count++;
277 buf[offset] = 0;
278 }
[2677758]279 }
[ac8e7a9]280
[c583970]281 return count;
[2677758]282}
283
[ac8e7a9]284/** Get character from input device & echo it to screen */
[c583970]285wchar_t getc(indev_t *indev)
[2677758]286{
[44b7783]287 wchar_t ch = indev_pop_character(indev);
[e8a9dc3]288 putchar(ch);
[2677758]289 return ch;
290}
[973be64e]291
[6fa9a99d]292void kio_update(void *event)
[82b71ef1]293{
[6fa9a99d]294 if (!atomic_get(&kio_inited))
[712c4ba]295 return;
296
[6fa9a99d]297 spinlock_lock(&kio_lock);
[82b71ef1]298
[6fa9a99d]299 if (kio_uspace > 0) {
300 if (event_notify_3(EVENT_KIO, true, kio_start, kio_len,
301 kio_uspace) == EOK)
302 kio_uspace = 0;
[05641a9e]303 }
[82b71ef1]304
[6fa9a99d]305 spinlock_unlock(&kio_lock);
[82b71ef1]306}
307
[91db0280]308/** Flush characters that are stored in the output buffer
[7ddc2c7]309 *
[91db0280]310 */
311void kio_flush(void)
[973be64e]312{
[712c4ba]313 bool ordy = ((stdout) && (stdout->op->write));
314
[91db0280]315 if (!ordy)
316 return;
317
[6fa9a99d]318 spinlock_lock(&kio_lock);
[91db0280]319
320 /* Print characters that weren't printed earlier */
321 while (kio_stored > 0) {
322 wchar_t tmp = kio[(kio_start + kio_len - kio_stored) % KIO_LENGTH];
323 kio_stored--;
324
325 /*
326 * We need to give up the spinlock for
327 * the physical operation of writing out
328 * the character.
329 */
330 spinlock_unlock(&kio_lock);
331 stdout->op->write(stdout, tmp);
332 spinlock_lock(&kio_lock);
[c859753]333 }
[91db0280]334
335 spinlock_unlock(&kio_lock);
336}
337
338/** Put a character into the output buffer.
[7ddc2c7]339 *
[91db0280]340 * The caller is required to hold kio_lock
341 */
342void kio_push_char(const wchar_t ch)
343{
[6fa9a99d]344 kio[(kio_start + kio_len) % KIO_LENGTH] = ch;
345 if (kio_len < KIO_LENGTH)
346 kio_len++;
[c859753]347 else
[6fa9a99d]348 kio_start = (kio_start + 1) % KIO_LENGTH;
[c859753]349
[91db0280]350 if (kio_stored < kio_len)
351 kio_stored++;
[712c4ba]352
353 /* The character is stored for uspace */
[6fa9a99d]354 if (kio_uspace < kio_len)
355 kio_uspace++;
[91db0280]356}
357
358void putchar(const wchar_t ch)
359{
360 bool ordy = ((stdout) && (stdout->op->write));
[712c4ba]361
[91db0280]362 spinlock_lock(&kio_lock);
363 kio_push_char(ch);
[6fa9a99d]364 spinlock_unlock(&kio_lock);
[712c4ba]365
[91db0280]366 /* Output stored characters */
367 kio_flush();
368
369 if (!ordy) {
[da52547]370 /*
371 * No standard output routine defined yet.
372 * The character is still stored in the kernel log
373 * for possible future output.
374 *
375 * The early_putchar() function is used to output
376 * the character for low-level debugging purposes.
377 * Note that the early_putc() function might be
378 * a no-op on certain hardware configurations.
379 */
380 early_putchar(ch);
[c859753]381 }
[82b71ef1]382
[97d42d5]383 /* Force notification on newline */
384 if (ch == '\n')
[6fa9a99d]385 kio_update(NULL);
[973be64e]386}
[b45c443]387
[312cc68]388/** Print using kernel facility
389 *
390 * Print to kernel log.
391 *
392 */
[6fa9a99d]393sysarg_t sys_kio(int cmd, const void *buf, size_t size)
[312cc68]394{
395 char *data;
396 int rc;
[a801688b]397
398 switch (cmd) {
[6fa9a99d]399 case KIO_UPDATE:
400 kio_update(NULL);
[a801688b]401 return EOK;
[6fa9a99d]402 case KIO_WRITE:
403 case KIO_COMMAND:
[a801688b]404 break;
405 default:
406 return ENOTSUP;
407 }
408
[c583970]409 if (size > PAGE_SIZE)
[96b02eb9]410 return (sysarg_t) ELIMIT;
[312cc68]411
[c583970]412 if (size > 0) {
413 data = (char *) malloc(size + 1, 0);
[312cc68]414 if (!data)
[96b02eb9]415 return (sysarg_t) ENOMEM;
[312cc68]416
[c583970]417 rc = copy_from_uspace(data, buf, size);
[312cc68]418 if (rc) {
419 free(data);
[96b02eb9]420 return (sysarg_t) rc;
[312cc68]421 }
[c583970]422 data[size] = 0;
[312cc68]423
[297cb73]424 switch (cmd) {
[6fa9a99d]425 case KIO_WRITE:
[297cb73]426 printf("%s", data);
427 break;
[6fa9a99d]428 case KIO_COMMAND:
[11527051]429 if (!stdin)
430 break;
[297cb73]431 for (unsigned int i = 0; i < size; i++)
432 indev_push_character(stdin, data[i]);
433 indev_push_character(stdin, '\n');
434 break;
435 }
436
[312cc68]437 free(data);
[297cb73]438 }
439
[6afc9d7]440 return EOK;
[312cc68]441}
442
[06e1e95]443/** @}
[b45c443]444 */
Note: See TracBrowser for help on using the repository browser.