PatchworkOS  c9fea19
A non-POSIX operating system.
Loading...
Searching...
No Matches
log.c
Go to the documentation of this file.
1#include <kernel/log/log.h>
2
3#include <kernel/cpu/cpu.h>
10#include <kernel/sync/lock.h>
11
12#include <boot/boot_info.h>
13#include <kernel/version.h>
14
15#include <stdarg.h>
16#include <stdint.h>
17#include <stdio.h>
18#include <sys/io.h>
19#include <sys/proc.h>
20
22
23static char lineBuffer[LOG_MAX_BUFFER] = {0};
24static char workingBuffer[LOG_MAX_BUFFER] = {0};
27static bool isLastCharNewline = 0;
28static bool firstHeaderPrinted = false;
29
30static const char* levelNames[] = {
31 [LOG_LEVEL_DEBUG] = "D",
32 [LOG_LEVEL_USER] = "U",
33 [LOG_LEVEL_INFO] = "I",
34 [LOG_LEVEL_WARN] = "W",
35 [LOG_LEVEL_ERR] = "E",
36 [LOG_LEVEL_PANIC] = "P",
37};
38
39static void log_splash(void)
40{
41#ifdef NDEBUG
42 LOG_INFO("Booting %s-kernel %s (Built %s %s)\n", OS_NAME, OS_VERSION, __DATE__, __TIME__);
43#else
44 LOG_INFO("Booting %s-kernel DEBUG %s (Built %s %s)\n", OS_NAME, OS_VERSION, __DATE__, __TIME__);
45#endif
46 LOG_INFO("Copyright (C) 2025 Kai Norberg. MIT Licensed. See /usr/license/LICENSE for details.\n");
47 LOG_INFO("min_level=%s outputs=%s%s%s\n", levelNames[minLevel], (outputs & LOG_OUTPUT_SERIAL) ? "serial " : "",
48 (outputs & LOG_OUTPUT_SCREEN) ? "screen " : "", (outputs & LOG_OUTPUT_FILE) ? "file " : "");
49}
50
51void log_init(void)
52{
54 const boot_gop_t* gop = &bootInfo->gop;
55
57
58 outputs = 0;
59#ifndef NDEBUG
61#else
63#endif
64 isLastCharNewline = true;
65
68#if CONFIG_LOG_SERIAL
71#endif
72
73 log_splash();
74}
75
77{
79
81 {
82 return;
83 }
84
87}
88
90{
92
93 outputs &= ~LOG_OUTPUT_SCREEN;
94}
95
96static void log_write(const char* string, uint64_t length)
97{
99 {
100 log_file_write(string, length);
101 }
102
104 {
105 for (uint64_t i = 0; i < length; i++)
106 {
107 com_write(COM1, string[i]);
108 }
109 }
110
112 {
113 log_screen_write(string, length);
114 }
115}
116
118{
120 {
121 firstHeaderPrinted = true;
122 }
123 else
124 {
125 log_write("\n", 1);
126 }
127
128 if (level == LOG_LEVEL_PANIC)
129 {
130 int length = snprintf(workingBuffer, sizeof(workingBuffer), "[XXXX.XXX-XX-X] ");
131 log_write(workingBuffer, length);
132 return;
133 }
134
136 uint64_t seconds = uptime / CLOCKS_PER_SEC;
137 uint64_t milliseconds = (uptime % CLOCKS_PER_SEC) / (CLOCKS_PER_SEC / 1000);
138
139 cpu_t* self = cpu_get_unsafe();
140
141 int length = snprintf(workingBuffer, sizeof(workingBuffer), "[%4llu.%03llu-%02x-%s] ", seconds, milliseconds,
142 self->id, levelNames[level]);
143 log_write(workingBuffer, length);
144}
145
146static void log_handle_char(log_level_t level, char chr)
147{
148 if (isLastCharNewline && chr != '\n')
149 {
150 isLastCharNewline = false;
151
152 log_print_header(level);
153 }
154
155 if (chr == '\n')
156 {
158 {
159 log_print_header(level);
160 }
161 isLastCharNewline = true;
162 return;
163 }
164
165 log_write(&chr, 1);
166}
167
168void log_nprint(log_level_t level, const char* string, uint64_t length)
169{
170 if (level < minLevel)
171 {
172 return;
173 }
174
175 if (level != LOG_LEVEL_PANIC)
176 {
178 }
179
180 for (uint64_t i = 0; i < length; i++)
181 {
182 log_handle_char(level, string[i]);
183 }
184
185 if (level != LOG_LEVEL_PANIC)
186 {
188 }
189}
190
191void log_print(log_level_t level, const char* format, ...)
192{
193 va_list args;
194 va_start(args, format);
195 log_vprint(level, format, args);
196 va_end(args);
197}
198
199void log_vprint(log_level_t level, const char* format, va_list args)
200{
201 if (level < minLevel)
202 {
203 return;
204 }
205
206 if (level != LOG_LEVEL_PANIC)
207 {
209 }
210
211 int length = vsnprintf(lineBuffer, LOG_MAX_BUFFER, format, args);
212 assert(length >= 0);
213
214 if (length >= LOG_MAX_BUFFER)
215 {
216 length = LOG_MAX_BUFFER - 1;
217 lineBuffer[length] = '\0';
218 }
219
220 for (int i = 0; i < length; i++)
221 {
222 log_handle_char(level, lineBuffer[i]);
223 }
224
225 if (level != LOG_LEVEL_PANIC)
226 {
228 }
229}
#define assert(expression)
Definition assert.h:29
boot_info_t * bootInfo
Definition boot_info.c:14
#define CLOCKS_PER_SEC
Definition clock_t.h:15
@ COM1
Definition com.h:7
void com_write(com_port_t port, uint8_t value)
Definition com.c:23
void com_init(com_port_t port)
Definition com.c:4
static cpu_t * cpu_get_unsafe(void)
Gets the current CPU structure without disabling interrupts.
Definition cpu.h:299
boot_info_t * boot_info_get(void)
Gets the boot info structure.
Definition boot_info.c:16
void log_file_flush_to_screen(void)
Flush the content of the log file to the screen.
Definition log_file.c:89
void log_file_write(const char *string, uint64_t length)
Write a string to the kernel log file.
Definition log_file.c:129
void log_screen_write(const char *string, uint64_t length)
Write a string to the screen.
Definition log_screen.c:204
void log_screen_init(const boot_gop_t *bootGop)
Initialize the screen logging.
Definition log_screen.c:83
void log_init(void)
Initialize the logging system.
Definition log.c:51
void log_print(log_level_t level, const char *format,...)
Print a formatted log message.
Definition log.c:191
#define LOG_INFO(format,...)
Definition log.h:106
#define LOG_MAX_BUFFER
Maximum buffer size for various logging buffers.
Definition log.h:25
log_level_t
Log levels.
Definition log.h:41
void log_screen_disable(void)
Disable logging to the screen.
Definition log.c:89
void log_nprint(log_level_t level, const char *string, uint64_t length)
Print a unformatted log message.
Definition log.c:168
void log_vprint(log_level_t level, const char *format, va_list args)
Print a formatted log message with a va_list.
Definition log.c:199
void log_screen_enable()
Enable logging to the screen.
Definition log.c:76
log_output_t
Logging output options.
Definition log.h:31
@ LOG_LEVEL_ERR
Definition log.h:46
@ LOG_LEVEL_DEBUG
Definition log.h:42
@ LOG_LEVEL_USER
Definition log.h:43
@ LOG_LEVEL_WARN
Definition log.h:45
@ LOG_LEVEL_PANIC
Definition log.h:47
@ LOG_LEVEL_INFO
Definition log.h:44
@ LOG_OUTPUT_SCREEN
Definition log.h:33
@ LOG_OUTPUT_SERIAL
Definition log.h:32
@ LOG_OUTPUT_FILE
Definition log.h:34
clock_t clock_uptime(void)
Retrieve the time in nanoseconds since boot.
Definition clock.c:99
#define LOCK_CREATE()
Create a lock initializer.
Definition lock.h:68
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:57
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:146
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:103
clock_t uptime(void)
System call for retreving the time since boot.
Definition uptime.c:6
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static void log_splash(void)
Definition log.c:39
static log_level_t minLevel
Definition log.c:26
static log_output_t outputs
Definition log.c:25
static const char * levelNames[]
Definition log.c:30
static lock_t lock
Definition log.c:21
static bool isLastCharNewline
Definition log.c:27
static char lineBuffer[LOG_MAX_BUFFER]
Definition log.c:23
static void log_handle_char(log_level_t level, char chr)
Definition log.c:146
static void log_print_header(log_level_t level)
Definition log.c:117
static char workingBuffer[LOG_MAX_BUFFER]
Definition log.c:24
static bool firstHeaderPrinted
Definition log.c:28
static void log_write(const char *string, uint64_t length)
Definition log.c:96
boot_gop_t * gop
Definition mem.c:18
#define va_start(ap, parmN)
Definition stdarg.h:14
#define va_end(ap)
Definition stdarg.h:13
__builtin_va_list va_list
Definition stdarg.h:9
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC int vsnprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format, va_list arg)
Definition vsnprintf.c:5
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
boot_gop_t gop
Definition boot_info.h:101
CPU structure.
Definition cpu.h:122
cpuid_t id
Definition cpu.h:123
A simple ticket lock implementation.
Definition lock.h:43