1 /*
2 * Copyright (c) 2008-2015 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <lib/io.h>
9
10 #include <lk/err.h>
11 #include <ctype.h>
12 #include <lk/debug.h>
13 #include <assert.h>
14 #include <lk/list.h>
15 #include <string.h>
16 #include <lib/cbuf.h>
17 #include <arch/ops.h>
18 #include <platform.h>
19 #include <platform/debug.h>
20 #include <kernel/thread.h>
21 #include <lk/init.h>
22
23 /* routines for dealing with main console io */
24
25 #if WITH_LIB_SM
26 #define PRINT_LOCK_FLAGS SPIN_LOCK_FLAG_IRQ_FIQ
27 #else
28 #define PRINT_LOCK_FLAGS SPIN_LOCK_FLAG_INTERRUPTS
29 #endif
30
31 static spin_lock_t print_spin_lock = 0;
32 static struct list_node print_callbacks = LIST_INITIAL_VALUE(print_callbacks);
33
34 #if CONSOLE_HAS_INPUT_BUFFER
35 #ifndef CONSOLE_BUF_LEN
36 #define CONSOLE_BUF_LEN 256
37 #endif
38
39 /* global input circular buffer */
40 cbuf_t console_input_cbuf;
41 static uint8_t console_cbuf_buf[CONSOLE_BUF_LEN];
42 #endif // CONSOLE_HAS_INPUT_BUFFER
43
44 /* print lock must be held when invoking out, outs, outc */
out_count(const char * str,size_t len)45 static void out_count(const char *str, size_t len) {
46 print_callback_t *cb;
47
48 /* print to any registered loggers */
49 if (!list_is_empty(&print_callbacks)) {
50 spin_lock_saved_state_t state;
51 spin_lock_save(&print_spin_lock, &state, PRINT_LOCK_FLAGS);
52
53 list_for_every_entry(&print_callbacks, cb, print_callback_t, entry) {
54 if (cb->print)
55 cb->print(cb, str, len);
56 }
57
58 spin_unlock_restore(&print_spin_lock, state, PRINT_LOCK_FLAGS);
59 }
60
61 #if CONSOLE_OUTPUT_TO_PLATFORM_PUTC
62 size_t i;
63 /* write out the serial port */
64 for (i = 0; i < len; i++) {
65 platform_dputc(str[i]);
66 }
67 #endif
68 }
69
register_print_callback(print_callback_t * cb)70 void register_print_callback(print_callback_t *cb) {
71 spin_lock_saved_state_t state;
72 spin_lock_save(&print_spin_lock, &state, PRINT_LOCK_FLAGS);
73
74 list_add_head(&print_callbacks, &cb->entry);
75
76 spin_unlock_restore(&print_spin_lock, state, PRINT_LOCK_FLAGS);
77 }
78
unregister_print_callback(print_callback_t * cb)79 void unregister_print_callback(print_callback_t *cb) {
80 spin_lock_saved_state_t state;
81 spin_lock_save(&print_spin_lock, &state, PRINT_LOCK_FLAGS);
82
83 list_delete(&cb->entry);
84
85 spin_unlock_restore(&print_spin_lock, state, PRINT_LOCK_FLAGS);
86 }
87
__debug_stdio_write(io_handle_t * io,const char * s,size_t len)88 static ssize_t __debug_stdio_write(io_handle_t *io, const char *s, size_t len) {
89 out_count(s, len);
90 return len;
91 }
92
__debug_stdio_read(io_handle_t * io,char * s,size_t len)93 static ssize_t __debug_stdio_read(io_handle_t *io, char *s, size_t len) {
94 if (len == 0)
95 return 0;
96
97 #if CONSOLE_HAS_INPUT_BUFFER
98 ssize_t err = cbuf_read(&console_input_cbuf, s, len, true);
99 return err;
100 #else
101 int err = platform_dgetc(s, true);
102 if (err < 0)
103 return err;
104
105 return 1;
106 #endif
107 }
108
109 #if CONSOLE_HAS_INPUT_BUFFER
console_init_hook(uint level)110 static void console_init_hook(uint level) {
111 cbuf_initialize_etc(&console_input_cbuf, sizeof(console_cbuf_buf), console_cbuf_buf);
112 }
113
114 LK_INIT_HOOK(console, console_init_hook, LK_INIT_LEVEL_PLATFORM_EARLY - 1);
115 #endif
116
117 /* global console io handle */
118 static const io_handle_hooks_t console_io_hooks = {
119 .write = __debug_stdio_write,
120 .read = __debug_stdio_read,
121 };
122
123 io_handle_t console_io = IO_HANDLE_INITIAL_VALUE(&console_io_hooks);
124
125