PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
log.c
Go to the documentation of this file.
1#include <kernel/fs/devfs.h>
2#include <kernel/fs/file.h>
3#include <kernel/log/log.h>
4
5#include <kernel/cpu/cpu.h>
8#include <kernel/log/screen.h>
10#include <kernel/sched/timer.h>
11#include <kernel/sched/wait.h>
12#include <kernel/sync/lock.h>
13
14#include <boot/boot_info.h>
15#include <kernel/version.h>
16
17#include <stdarg.h>
18#include <stdint.h>
19#include <stdio.h>
20#include <string.h>
21#include <sys/fs.h>
22#include <sys/math.h>
23#include <sys/proc.h>
24
26
28static uint64_t klogHead = 0;
29static dentry_t* klog = NULL;
30
31static char lineBuffer[LOG_MAX_BUFFER] = {0};
32static char workingBuffer[LOG_MAX_BUFFER] = {0};
33static bool isLastCharNewline = false;
34static bool firstHeaderPrinted = false;
35
36static const char* levelNames[] = {
37 [LOG_LEVEL_DEBUG] = "D",
38 [LOG_LEVEL_USER] = "U",
39 [LOG_LEVEL_INFO] = "I",
40 [LOG_LEVEL_WARN] = "W",
41 [LOG_LEVEL_ERR] = "E",
42 [LOG_LEVEL_PANIC] = "P",
43};
44
45static size_t klog_read(file_t* file, void* buffer, size_t count, size_t* offset)
46{
47 UNUSED(file);
48
50
51 if (*offset >= klogHead)
52 {
53 return 0;
54 }
55
56 for (size_t i = 0; i < count; i++)
57 {
58 if (*offset >= klogHead)
59 {
60 return i;
61 }
62
63 ((char*)buffer)[i] = klogBuffer[(*offset)++ % CONFIG_KLOG_SIZE];
64 }
65
66 return count;
67}
68
69static size_t klog_write(file_t* file, const void* buffer, size_t count, size_t* offset)
70{
71 UNUSED(file);
73
75 return count;
76}
77
79 .read = klog_read,
80 .write = klog_write,
81};
82
83static void log_splash(void)
84{
85#ifdef NDEBUG
86 LOG_INFO("Booting %s-kernel %s (Built %s %s)\n", OS_NAME, OS_VERSION, __DATE__, __TIME__);
87#else
88 LOG_INFO("Booting %s-kernel DEBUG %s (Built %s %s)\n", OS_NAME, OS_VERSION, __DATE__, __TIME__);
89#endif
90 LOG_INFO("Copyright (C) 2025 Kai Norberg. MIT Licensed.\n");
91}
92
93void log_init(void)
94{
97
98 const boot_gop_t* gop = &bootInfo->gop;
100
101 isLastCharNewline = true;
102
103 screen_init();
104
105#if CONFIG_LOG_SERIAL
106 com_init(COM1);
107#endif
108
109 log_splash();
110}
111
112void log_expose(void)
113{
115
116 if (klog != NULL)
117 {
118 return;
119 }
120
121 klog = devfs_file_new(NULL, "klog", NULL, &klogOps, NULL);
122 if (klog == NULL)
123 {
124 return;
125 }
126}
127
128static void log_write(const char* string, uint64_t length)
129{
130 for (uint64_t i = 0; i < length; i++)
131 {
132 klogBuffer[klogHead++ % CONFIG_KLOG_SIZE] = string[i];
133 }
134
135#if CONFIG_LOG_SERIAL
136 for (uint64_t i = 0; i < length; i++)
137 {
138 com_write(COM1, string[i]);
139 }
140#endif
141
142 screen_write(string, length);
143}
144
146{
148 {
149 firstHeaderPrinted = true;
150 }
151 else
152 {
153 log_write("\n", 1);
154 }
155
156 if (level == LOG_LEVEL_PANIC)
157 {
158 int length = snprintf(workingBuffer, sizeof(workingBuffer), "[XXXX.XXX-XX-X] ");
159 log_write(workingBuffer, length);
160 return;
161 }
162
164 uint64_t seconds = uptime / CLOCKS_PER_SEC;
165 uint64_t milliseconds = (uptime % CLOCKS_PER_SEC) / (CLOCKS_PER_MS);
166
167 int length = snprintf(workingBuffer, sizeof(workingBuffer), "[%4llu.%03llu-%02x-%s] ", seconds, milliseconds,
168 SELF->id, levelNames[level]);
169 log_write(workingBuffer, length);
170}
171
172static void log_handle_char(log_level_t level, char chr)
173{
174 if (isLastCharNewline && chr != '\n')
175 {
176 isLastCharNewline = false;
177
178 log_print_header(level);
179 }
180
181 if (chr == '\n')
182 {
184 {
185 log_print_header(level);
186 }
187 isLastCharNewline = true;
188 return;
189 }
190
191 log_write(&chr, 1);
192}
193
194void log_nprint(log_level_t level, const char* string, uint64_t length)
195{
196 if (level != LOG_LEVEL_PANIC)
197 {
199 }
200
201 for (uint64_t i = 0; i < length; i++)
202 {
203 log_handle_char(level, string[i]);
204 }
205
206 if (level != LOG_LEVEL_PANIC)
207 {
209 }
210}
211
212void log_print(log_level_t level, const char* format, ...)
213{
214 va_list args;
215 va_start(args, format);
216 log_vprint(level, format, args);
217 va_end(args);
218}
219
220void log_vprint(log_level_t level, const char* format, va_list args)
221{
222 if (level != LOG_LEVEL_PANIC)
223 {
225 }
226
227 int length = vsnprintf(lineBuffer, LOG_MAX_BUFFER, format, args);
228 assert(length >= 0);
229
230 if (length >= LOG_MAX_BUFFER)
231 {
232 length = LOG_MAX_BUFFER - 1;
233 lineBuffer[length] = '\0';
234 }
235
236 for (int i = 0; i < length; i++)
237 {
238 log_handle_char(level, lineBuffer[i]);
239 }
240
241 if (level != LOG_LEVEL_PANIC)
242 {
244 }
245}
#define assert(expression)
Definition assert.h:29
boot_gop_t * gop
Definition main.c:240
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
boot_info_t * bootInfo
Definition boot_info.c:14
static char format[MAX_NAME]
Definition screen.c:17
#define CLOCKS_PER_SEC
Definition clock_t.h:15
#define CLOCKS_PER_MS
Definition clock_t.h:16
@ 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
#define CONFIG_KLOG_SIZE
Definition config.h:164
#define SELF
Macro to access data in the current cpu.
Definition percpu.h:85
dentry_t * devfs_file_new(dentry_t *parent, const char *name, const vnode_ops_t *vnodeOps, const file_ops_t *fileOps, void *data)
Create a new file inside a mounted devfs instance.
Definition devfs.c:121
boot_info_t * boot_info_get(void)
Gets the boot info structure.
Definition boot_info.c:16
void screen_init(void)
Initialize and enable the screen logging.
Definition screen.c:80
void screen_write(const char *string, uint64_t length)
Write a string to the screen.
Definition screen.c:229
void log_init(void)
Initialize the logging system.
Definition log.c:93
void log_print(log_level_t level, const char *format,...)
Print a formatted log message.
Definition log.c:212
#define LOG_INFO(format,...)
Definition log.h:91
#define LOG_MAX_BUFFER
Maximum buffer size for various logging buffers.
Definition log.h:25
log_level_t
Log levels.
Definition log.h:31
void log_nprint(log_level_t level, const char *string, uint64_t length)
Print a unformatted log message.
Definition log.c:194
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:220
void log_expose(void)
Expose kernel logs via the /dev/klog file.
Definition log.c:112
@ LOG_LEVEL_ERR
Definition log.h:36
@ LOG_LEVEL_DEBUG
Definition log.h:32
@ LOG_LEVEL_USER
Definition log.h:33
@ LOG_LEVEL_WARN
Definition log.h:35
@ LOG_LEVEL_PANIC
Definition log.h:37
@ LOG_LEVEL_INFO
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:69
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:58
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:175
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:96
#define UNUSED(x)
Mark a variable as unused.
Definition defs.h:96
clock_t uptime(void)
System call for retreving the time since boot.
Definition uptime.c:6
#define NULL
Pointer error value.
Definition NULL.h:25
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
static uint64_t offset
Definition screen.c:19
static void log_splash(void)
Definition log.c:83
static size_t klog_write(file_t *file, const void *buffer, size_t count, size_t *offset)
Definition log.c:69
static const char * levelNames[]
Definition log.c:36
static uint64_t klogHead
Definition log.c:28
static lock_t lock
Definition log.c:25
static size_t klog_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition log.c:45
static bool isLastCharNewline
Definition log.c:33
static file_ops_t klogOps
Definition log.c:78
static char lineBuffer[LOG_MAX_BUFFER]
Definition log.c:31
static void log_handle_char(log_level_t level, char chr)
Definition log.c:172
static void log_print_header(log_level_t level)
Definition log.c:145
static char workingBuffer[LOG_MAX_BUFFER]
Definition log.c:32
static bool firstHeaderPrinted
Definition log.c:34
static void log_write(const char *string, uint64_t length)
Definition log.c:128
static dentry_t * klog
Definition log.c:29
static char klogBuffer[CONFIG_KLOG_SIZE]
Definition log.c:27
static atomic_long count
Definition main.c:11
#define va_start(ap, parmN)
Definition stdarg.h:16
#define va_end(ap)
Definition stdarg.h:15
__builtin_va_list va_list
Definition stdarg.h:11
__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:31
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
uint32_t * virtAddr
Definition boot_info.h:45
boot_gop_t gop
Definition boot_info.h:101
Directory entry structure.
Definition dentry.h:155
File operations structure.
Definition file.h:54
size_t(* read)(file_t *file, void *buffer, size_t count, size_t *offset)
Definition file.h:58
File structure.
Definition file.h:39
A simple ticket lock implementation.
Definition lock.h:44