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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fc0de8c was 5a5269d, checked in by GitHub <noreply@…>, 6 years ago

Change type of uspace pointers in kernel from pointer type to numeric (#170)

From kernel's perspective, userspace addresses are not valid pointers,
and can only be used in calls to copy_to/from_uspace().
Therefore, we change the type of those arguments and variables to
uspace_addr_t which is an alias for sysarg_t.

This allows the compiler to catch accidental direct accesses to
userspace addresses.

Additionally, to avoid losing the type information in code,
a macro uspace_ptr(type) is used that translates to uspace_addr_t.
I makes no functional difference, but allows keeping the type information
in code in case we implement some sort of static checking for it in the future.

However, ccheck doesn't like that, so instead of using uspace_ptr(char),
we use uspace_ptr_char which is defined as
#define uspace_ptr_char uspace_ptr(char).

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