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     size_t i;
48 
49     /* print to any registered loggers */
50     if (!list_is_empty(&print_callbacks)) {
51         spin_lock_saved_state_t state;
52         spin_lock_save(&print_spin_lock, &state, PRINT_LOCK_FLAGS);
53 
54         list_for_every_entry(&print_callbacks, cb, print_callback_t, entry) {
55             if (cb->print)
56                 cb->print(cb, str, len);
57         }
58 
59         spin_unlock_restore(&print_spin_lock, state, PRINT_LOCK_FLAGS);
60     }
61 
62     /* write out the serial port */
63     for (i = 0; i < len; i++) {
64         platform_dputc(str[i]);
65     }
66 }
67 
register_print_callback(print_callback_t * cb)68 void register_print_callback(print_callback_t *cb) {
69     spin_lock_saved_state_t state;
70     spin_lock_save(&print_spin_lock, &state, PRINT_LOCK_FLAGS);
71 
72     list_add_head(&print_callbacks, &cb->entry);
73 
74     spin_unlock_restore(&print_spin_lock, state, PRINT_LOCK_FLAGS);
75 }
76 
unregister_print_callback(print_callback_t * cb)77 void unregister_print_callback(print_callback_t *cb) {
78     spin_lock_saved_state_t state;
79     spin_lock_save(&print_spin_lock, &state, PRINT_LOCK_FLAGS);
80 
81     list_delete(&cb->entry);
82 
83     spin_unlock_restore(&print_spin_lock, state, PRINT_LOCK_FLAGS);
84 }
85 
__debug_stdio_write(io_handle_t * io,const char * s,size_t len)86 static ssize_t __debug_stdio_write(io_handle_t *io, const char *s, size_t len) {
87     out_count(s, len);
88     return len;
89 }
90 
__debug_stdio_read(io_handle_t * io,char * s,size_t len)91 static ssize_t __debug_stdio_read(io_handle_t *io, char *s, size_t len) {
92     if (len == 0)
93         return 0;
94 
95 #if CONSOLE_HAS_INPUT_BUFFER
96     ssize_t err = cbuf_read(&console_input_cbuf, s, len, true);
97     return err;
98 #else
99     int err = platform_dgetc(s, true);
100     if (err < 0)
101         return err;
102 
103     return 1;
104 #endif
105 }
106 
107 #if CONSOLE_HAS_INPUT_BUFFER
console_init_hook(uint level)108 static void console_init_hook(uint level) {
109     cbuf_initialize_etc(&console_input_cbuf, sizeof(console_cbuf_buf), console_cbuf_buf);
110 }
111 
112 LK_INIT_HOOK(console, console_init_hook, LK_INIT_LEVEL_PLATFORM_EARLY - 1);
113 #endif
114 
115 /* global console io handle */
116 static const io_handle_hooks_t console_io_hooks = {
117     .write  = __debug_stdio_write,
118     .read   = __debug_stdio_read,
119 };
120 
121 io_handle_t console_io = IO_HANDLE_INITIAL_VALUE(&console_io_hooks);
122 
123