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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eed4139 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 9.7 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 <assert.h>
37#include <console/console.h>
38#include <console/chardev.h>
39#include <sysinfo/sysinfo.h>
40#include <synch/waitq.h>
41#include <synch/spinlock.h>
42#include <typedefs.h>
43#include <ddi/irq.h>
44#include <ddi/ddi.h>
45#include <ipc/event.h>
46#include <ipc/irq.h>
47#include <arch.h>
48#include <panic.h>
49#include <print.h>
50#include <putchar.h>
51#include <atomic.h>
52#include <syscall/copy.h>
53#include <errno.h>
54#include <str.h>
55#include <abi/kio.h>
56#include <mm/frame.h> /* SIZE2FRAMES */
57#include <mm/slab.h> /* malloc */
58
59#define KIO_PAGES 8
60#define KIO_LENGTH (KIO_PAGES * PAGE_SIZE / sizeof(wchar_t))
61
62/** Kernel log cyclic buffer */
63wchar_t kio[KIO_LENGTH] __attribute__((aligned(PAGE_SIZE)));
64
65/** Kernel log initialized */
66static atomic_t kio_inited = {false};
67
68/** First kernel log characters */
69static size_t kio_start = 0;
70
71/** Number of valid kernel log characters */
72static size_t kio_len = 0;
73
74/** Number of stored (not printed) kernel log characters */
75static size_t kio_stored = 0;
76
77/** Number of stored kernel log characters for uspace */
78static size_t kio_uspace = 0;
79
80/** Kernel log spinlock */
81SPINLOCK_INITIALIZE_NAME(kio_lock, "kio_lock");
82
83/** Physical memory area used for kio buffer */
84static parea_t kio_parea;
85
86static indev_t stdin_sink;
87static outdev_t stdout_source;
88
89static void stdin_signal(indev_t *, indev_signal_t);
90
91static indev_operations_t stdin_ops = {
92 .poll = NULL,
93 .signal = stdin_signal
94};
95
96static void stdout_write(outdev_t *, wchar_t);
97static void stdout_redraw(outdev_t *);
98static void stdout_scroll_up(outdev_t *);
99static void stdout_scroll_down(outdev_t *);
100
101static outdev_operations_t stdout_ops = {
102 .write = stdout_write,
103 .redraw = stdout_redraw,
104 .scroll_up = stdout_scroll_up,
105 .scroll_down = stdout_scroll_down
106};
107
108/** Override kernel console lockout */
109bool console_override = false;
110
111/** Standard input and output character devices */
112indev_t *stdin = NULL;
113outdev_t *stdout = NULL;
114
115indev_t *stdin_wire(void)
116{
117 if (stdin == NULL) {
118 indev_initialize("stdin", &stdin_sink, &stdin_ops);
119 stdin = &stdin_sink;
120 }
121
122 return stdin;
123}
124
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
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
149static void stdout_write(outdev_t *dev, wchar_t ch)
150{
151 list_foreach(dev->list, link, outdev_t, sink) {
152 if ((sink) && (sink->op->write))
153 sink->op->write(sink, ch);
154 }
155}
156
157static void stdout_redraw(outdev_t *dev)
158{
159 list_foreach(dev->list, link, outdev_t, sink) {
160 if ((sink) && (sink->op->redraw))
161 sink->op->redraw(sink);
162 }
163}
164
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
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.
186 *
187 */
188void kio_init(void)
189{
190 void *faddr = (void *) KA2PA(kio);
191
192 assert((uintptr_t) faddr % FRAME_SIZE == 0);
193
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);
199
200 sysinfo_set_item_val("kio.faddr", NULL, (sysarg_t) faddr);
201 sysinfo_set_item_val("kio.pages", NULL, KIO_PAGES);
202
203 event_set_unmask_callback(EVENT_KIO, kio_update);
204 atomic_set(&kio_inited, true);
205}
206
207void grab_console(void)
208{
209 event_notify_1(EVENT_KCONSOLE, false, true);
210 bool prev = console_override;
211
212 console_override = true;
213 if ((stdout) && (stdout->op->redraw))
214 stdout->op->redraw(stdout);
215
216 if ((stdin) && (!prev)) {
217 /*
218 * Force the console to print the prompt.
219 */
220 indev_push_character(stdin, '\n');
221 }
222}
223
224void release_console(void)
225{
226 console_override = false;
227 event_notify_1(EVENT_KCONSOLE, false, false);
228}
229
230/** Activate kernel console override */
231sysarg_t sys_debug_console(void)
232{
233#ifdef CONFIG_KCONSOLE
234 grab_console();
235 return true;
236#else
237 return false;
238#endif
239}
240
241/** Get string from input character device.
242 *
243 * Read characters from input character device until first occurrence
244 * of newline character.
245 *
246 * @param indev Input character device.
247 * @param buf Buffer where to store string terminated by NULL.
248 * @param buflen Size of the buffer.
249 *
250 * @return Number of characters read.
251 *
252 */
253size_t gets(indev_t *indev, char *buf, size_t buflen)
254{
255 size_t offset = 0;
256 size_t count = 0;
257 buf[offset] = 0;
258
259 wchar_t ch;
260 while ((ch = indev_pop_character(indev)) != '\n') {
261 if (ch == '\b') {
262 if (count > 0) {
263 /* Space, backspace, space */
264 putchar('\b');
265 putchar(' ');
266 putchar('\b');
267
268 count--;
269 offset = str_lsize(buf, count);
270 buf[offset] = 0;
271 }
272 }
273
274 if (chr_encode(ch, buf, &offset, buflen - 1) == EOK) {
275 putchar(ch);
276 count++;
277 buf[offset] = 0;
278 }
279 }
280
281 return count;
282}
283
284/** Get character from input device & echo it to screen */
285wchar_t getc(indev_t *indev)
286{
287 wchar_t ch = indev_pop_character(indev);
288 putchar(ch);
289 return ch;
290}
291
292void kio_update(void *event)
293{
294 if (!atomic_get(&kio_inited))
295 return;
296
297 spinlock_lock(&kio_lock);
298
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;
303 }
304
305 spinlock_unlock(&kio_lock);
306}
307
308/** Flush characters that are stored in the output buffer
309 *
310 */
311void kio_flush(void)
312{
313 bool ordy = ((stdout) && (stdout->op->write));
314
315 if (!ordy)
316 return;
317
318 spinlock_lock(&kio_lock);
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);
333 }
334
335 spinlock_unlock(&kio_lock);
336}
337
338/** Put a character into the output buffer.
339 *
340 * The caller is required to hold kio_lock
341 */
342void kio_push_char(const wchar_t ch)
343{
344 kio[(kio_start + kio_len) % KIO_LENGTH] = ch;
345 if (kio_len < KIO_LENGTH)
346 kio_len++;
347 else
348 kio_start = (kio_start + 1) % KIO_LENGTH;
349
350 if (kio_stored < kio_len)
351 kio_stored++;
352
353 /* The character is stored for uspace */
354 if (kio_uspace < kio_len)
355 kio_uspace++;
356}
357
358void putchar(const wchar_t ch)
359{
360 bool ordy = ((stdout) && (stdout->op->write));
361
362 spinlock_lock(&kio_lock);
363 kio_push_char(ch);
364 spinlock_unlock(&kio_lock);
365
366 /* Output stored characters */
367 kio_flush();
368
369 if (!ordy) {
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);
381 }
382
383 /* Force notification on newline */
384 if (ch == '\n')
385 kio_update(NULL);
386}
387
388/** Print using kernel facility
389 *
390 * Print to kernel log.
391 *
392 */
393sys_errno_t sys_kio(int cmd, const void *buf, size_t size)
394{
395 char *data;
396 errno_t rc;
397
398 switch (cmd) {
399 case KIO_UPDATE:
400 kio_update(NULL);
401 return EOK;
402 case KIO_WRITE:
403 case KIO_COMMAND:
404 break;
405 default:
406 return ENOTSUP;
407 }
408
409 if (size > PAGE_SIZE)
410 return (sys_errno_t) ELIMIT;
411
412 if (size > 0) {
413 data = (char *) malloc(size + 1, 0);
414 if (!data)
415 return (sys_errno_t) ENOMEM;
416
417 rc = copy_from_uspace(data, buf, size);
418 if (rc) {
419 free(data);
420 return (sys_errno_t) rc;
421 }
422 data[size] = 0;
423
424 switch (cmd) {
425 case KIO_WRITE:
426 printf("%s", data);
427 break;
428 case KIO_COMMAND:
429 if (!stdin)
430 break;
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
437 free(data);
438 }
439
440 return EOK;
441}
442
443/** @}
444 */
Note: See TracBrowser for help on using the repository browser.