3 Copyright (C) 2009 Jörg Pfähler
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <libarch/scoped_lock.hpp>
20 #include <kernel/log.hpp>
21 #include <kernel/serial.hpp>
22 #include <kernel/console.hpp>
23 #include <kernel/processor.hpp>
25 using kernel::helper::tmp_log_entry
;
28 SINGLETON_INSTANCE(kernel::log
);
33 * Implementation of kernel::log
37 : m_beg(0), m_cur(0), m_cur_addr(virtual_memory::kernel_log_begin
<void>()),
38 m_cur_max_addr(adjust_pointer(virtual_memory::kernel_log_begin
<void>(), virtual_memory::page_size
))
47 void log::commit(const char* begin
,
49 libkernel::log_level lvl
)
51 #ifdef KERNEL_HAS_SERIAL
52 // Pump through the serial line before we do anything else
54 const char* tmp
= begin
;
55 serial
& Serial
= serial::instance();
56 while (LIKELY(tmp
!= end
))
62 if (LIKELY(lvl
!= libkernel::log_fatal
))
64 // Add the entry to the log
66 const size_t needed_size
= sizeof(entry
) + (end
- begin
) + 1;
68 while (UNLIKELY(pointer_difference(m_cur_max_addr
, m_cur_addr
) < needed_size
))
70 // TODO: Allocate space & map stuff (the fault tolerant way, perhaps tell serial if we
71 // swallowed a log entry because we ran out of memory)
74 entry
* new_entry
= reinterpret_cast<entry
*>(m_cur_addr
);
76 new_entry
->prev
= m_cur
;
78 if (UNLIKELY(m_cur
== 0))
81 m_cur
->next
= new_entry
;
83 m_cur_addr
= adjust_pointer(m_cur_addr
, needed_size
);
85 char* entry_string
= adjust_pointer_cast
<char>(new_entry
, sizeof(entry
));
86 while (LIKELY(begin
!= end
))
87 *entry_string
++ = *begin
++;
93 console
& Console
= console::instance();
94 console_window_ptr kernel_console
= Console
.get(kernel_console_id
);
96 // Write the log before the fatal message
101 size_t i
= console_window_height
- 2;
102 while (i
> 0 && cur
->prev
!= 0)
111 console_color_t color
= KERNEL_CONSOLE_NOTICE
;
112 if (cur
->lvl
== libkernel::log_warning
)
113 color
= KERNEL_CONSOLE_WARNING
;
114 else if (cur
->lvl
== libkernel::log_error
)
115 color
= KERNEL_CONSOLE_ERROR
;
117 const char* entry_string
= adjust_pointer_cast
<char>(cur
, sizeof(entry
));
118 while (*entry_string
!= '\0')
120 kernel_console
->character(cur_index
, *entry_string
++);
121 kernel_console
->color(cur_index
, color
);
124 cur_index
+= (console_window_width
- (cur_index
% console_window_width
)) % console_window_width
;
128 // Write the fatal error message
129 const char* fatal
= "FATAL: ";
130 while (*fatal
!= '\0')
132 kernel_console
->character(cur_index
, *fatal
++);
133 kernel_console
->color(cur_index
, KERNEL_CONSOLE_FATAL
);
139 kernel_console
->character(cur_index
, *begin
++);
140 kernel_console
->color(cur_index
, KERNEL_CONSOLE_FATAL
);
143 Console
.switch_to(kernel_console
);
145 // TODO: Fix this for multiprocessor environments
150 size_t log::get_entry(size_t index
,
151 libkernel::log_level
& lvl
,
155 SCOPED_LOCK(m_lock
, scope
);
158 while (cur
!= 0 && index
> 0)
167 size_t real_size
= 0;
168 char* entry_string
= adjust_pointer_cast
<char>(cur
, sizeof(entry
));
169 while (*entry_string
!= '\0' && size
>= 1)
171 *begin
++ = *entry_string
++;
178 } while (*entry_string
++ != '\0');
189 * Implementation of kernel::tmp_log_entry
192 tmp_log_entry::tmp_log_entry(libkernel::log_level lvl
)
193 : m_level(lvl
), m_first(virtual_memory::kernel_log_tmp_first
<char>()),
194 m_next(virtual_memory::kernel_log_tmp_first
<char>()), m_last(virtual_memory::kernel_log_tmp_last
<char>())
196 #if defined(_LIGHTOS_MULTIPROCESSOR)
197 log::instance().m_lock
.lock();
201 tmp_log_entry::~tmp_log_entry()
203 log::instance().commit(m_first
,
207 #if defined(_LIGHTOS_MULTIPROCESSOR)
208 log::instance().m_lock
.unlock();
212 tmp_log_entry
& tmp_log_entry::operator << (char c
)
214 if (m_next
!= m_last
)
219 tmp_log_entry
& tmp_log_entry::operator << (const char* s
)
222 tmp_log_entry::operator << (*s
++);
226 tmp_log_entry
& tmp_log_entry::operator << (const void* p
)
228 return *this << "0x" << hex(reinterpret_cast<uintptr_t>(p
), 2 * _LIBARCH_POINTER_SIZE
);