Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/PrintfImplementation.h>
28#include <AK/Types.h>
29#include <LibBareMetal/IO.h>
30#include <LibBareMetal/Output/Console.h>
31#include <LibBareMetal/Output/kstdio.h>
32
33#include <LibC/stdarg.h>
34
35#if defined(KERNEL)
36# include <Kernel/Process.h>
37#endif
38
39static bool serial_debug;
40
41void set_serial_debug(bool on_or_off)
42{
43 serial_debug = on_or_off;
44}
45
46int get_serial_debug()
47{
48 return serial_debug;
49}
50
51static void color_on()
52{
53 IO::out8(0xe9, 0x1b);
54 IO::out8(0xe9, '[');
55 IO::out8(0xe9, '3');
56 IO::out8(0xe9, '6');
57 IO::out8(0xe9, 'm');
58}
59
60static void color_off()
61{
62 IO::out8(0xe9, 0x1b);
63 IO::out8(0xe9, '[');
64 IO::out8(0xe9, '0');
65 IO::out8(0xe9, 'm');
66}
67
68static void serial_putch(char ch)
69{
70 static bool serial_ready = false;
71 static bool was_cr = false;
72
73 if (!serial_ready) {
74 IO::out8(0x3F8 + 1, 0x00);
75 IO::out8(0x3F8 + 3, 0x80);
76 IO::out8(0x3F8 + 0, 0x02);
77 IO::out8(0x3F8 + 1, 0x00);
78 IO::out8(0x3F8 + 3, 0x03);
79 IO::out8(0x3F8 + 2, 0xC7);
80 IO::out8(0x3F8 + 4, 0x0B);
81
82 serial_ready = true;
83 }
84
85 while ((IO::in8(0x3F8 + 5) & 0x20) == 0)
86 ;
87
88 if (ch == '\n' && !was_cr)
89 IO::out8(0x3F8, '\r');
90
91 IO::out8(0x3F8, ch);
92
93 if (ch == '\r')
94 was_cr = true;
95 else
96 was_cr = false;
97}
98
99static void console_putch(char*&, char ch)
100{
101 if (serial_debug)
102 serial_putch(ch);
103
104 // It would be bad to reach the assert in Console()::the() and do a stack overflow
105
106 if (Console::is_initialized()) {
107 Console::the().put_char(ch);
108 } else {
109 IO::out8(0xe9, ch);
110 }
111}
112
113int kprintf(const char* fmt, ...)
114{
115 color_on();
116 va_list ap;
117 va_start(ap, fmt);
118 int ret = printf_internal(console_putch, nullptr, fmt, ap);
119 va_end(ap);
120 color_off();
121 return ret;
122}
123
124static void buffer_putch(char*& bufptr, char ch)
125{
126 *bufptr++ = ch;
127}
128
129int sprintf(char* buffer, const char* fmt, ...)
130{
131 va_list ap;
132 va_start(ap, fmt);
133 int ret = printf_internal(buffer_putch, buffer, fmt, ap);
134 buffer[ret] = '\0';
135 va_end(ap);
136 return ret;
137}
138
139static void debugger_out(char ch)
140{
141 if (serial_debug)
142 serial_putch(ch);
143 IO::out8(0xe9, ch);
144}
145
146static void debugger_putch(char*&, char ch)
147{
148 debugger_out(ch);
149}
150
151extern "C" int dbgputstr(const char* characters, int length)
152{
153 for (int i = 0; i < length; ++i)
154 debugger_out(characters[i]);
155 return 0;
156}
157
158extern "C" int dbgprintf(const char* fmt, ...)
159{
160 color_on();
161 va_list ap;
162 va_start(ap, fmt);
163 int ret = printf_internal(debugger_putch, nullptr, fmt, ap);
164 va_end(ap);
165 color_off();
166 return ret;
167}