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