1 // Copyright 2016 The Fuchsia Authors
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 <arch/ops.h>
11 #include <assert.h>
12 #include <ctype.h>
13 #include <debug.h>
14 #include <err.h>
15 #include <kernel/auto_lock.h>
16 #include <kernel/thread.h>
17 #include <lib/debuglog.h>
18 #include <list.h>
19 #include <platform.h>
20 #include <platform/debug.h>
21 #include <string.h>
22 #include <vm/vm.h>
23
24 #include <lib/debuglog.h>
25
26 /* routines for dealing with main console io */
27
28 static SpinLock dputc_spin_lock;
29
__kernel_serial_write(const char * str,size_t len)30 void __kernel_serial_write(const char* str, size_t len) {
31 AutoSpinLock guard(&dputc_spin_lock);
32
33 /* write out the serial port */
34 platform_dputs_irq(str, len);
35 }
36
37 static SpinLock print_spin_lock;
38 static struct list_node print_callbacks = LIST_INITIAL_VALUE(print_callbacks);
39
__kernel_console_write(const char * str,size_t len)40 void __kernel_console_write(const char* str, size_t len) {
41 print_callback_t* cb;
42
43 /* print to any registered loggers */
44 if (!list_is_empty(&print_callbacks)) {
45 AutoSpinLock guard(&print_spin_lock);
46
47 list_for_every_entry (&print_callbacks, cb, print_callback_t, entry) {
48 if (cb->print)
49 cb->print(cb, str, len);
50 }
51 }
52 }
53
__kernel_stdout_write(const char * str,size_t len)54 static void __kernel_stdout_write(const char *str, size_t len)
55 {
56 if (dlog_bypass() == false) {
57 if (dlog_write(0, str, len) == ZX_OK)
58 return;
59 }
60 __kernel_console_write(str, len);
61 __kernel_serial_write(str, len);
62 }
63
64 #if WITH_DEBUG_LINEBUFFER
__kernel_stdout_write_buffered(const char * str,size_t len)65 static void __kernel_stdout_write_buffered(const char* str, size_t len) {
66 thread_t* t = get_current_thread();
67
68 if (unlikely(t == NULL)) {
69 __kernel_stdout_write(str, len);
70 return;
71 }
72
73 char* buf = t->linebuffer;
74 size_t pos = t->linebuffer_pos;
75
76 // look for corruption and don't continue
77 if (unlikely(!is_kernel_address((uintptr_t)buf) || pos >= THREAD_LINEBUFFER_LENGTH)) {
78 const char* str = "<linebuffer corruption>\n";
79 __kernel_stdout_write(str, strlen(str));
80 return;
81 }
82
83 while (len-- > 0) {
84 char c = *str++;
85 buf[pos++] = c;
86 if (c == '\n') {
87 __kernel_stdout_write(buf, pos);
88 pos = 0;
89 continue;
90 }
91 if (pos == (THREAD_LINEBUFFER_LENGTH - 1)) {
92 buf[pos++] = '\n';
93 __kernel_stdout_write(buf, pos);
94 pos = 0;
95 continue;
96 }
97 }
98 t->linebuffer_pos = pos;
99 }
100 #endif
101
register_print_callback(print_callback_t * cb)102 void register_print_callback(print_callback_t* cb) {
103 AutoSpinLock guard(&print_spin_lock);
104
105 list_add_head(&print_callbacks, &cb->entry);
106 }
107
unregister_print_callback(print_callback_t * cb)108 void unregister_print_callback(print_callback_t* cb) {
109 AutoSpinLock guard(&print_spin_lock);
110
111 list_delete(&cb->entry);
112 }
113
__printf_output_func(const char * s,size_t len,void * state)114 int __printf_output_func(const char* s, size_t len, void* state) {
115 #if WITH_DEBUG_LINEBUFFER
116 __kernel_stdout_write_buffered(s, len);
117 #else
118 __kernel_stdout_write(s, len);
119 #endif
120 return static_cast<int>(len);
121 }
122