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