]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
kernel: add console subsystem and kprintf (uart+vga)
authorTulio A M Mendes <[email protected]>
Sat, 7 Feb 2026 23:13:26 +0000 (20:13 -0300)
committerTulio A M Mendes <[email protected]>
Sat, 7 Feb 2026 23:13:26 +0000 (20:13 -0300)
include/console.h [new file with mode: 0644]
src/arch/x86/arch_platform.c
src/kernel/console.c [new file with mode: 0644]
src/kernel/main.c

diff --git a/include/console.h b/include/console.h
new file mode 100644 (file)
index 0000000..4f61e25
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef CONSOLE_H
+#define CONSOLE_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+void console_init(void);
+void console_enable_uart(int enabled);
+void console_enable_vga(int enabled);
+
+void console_write(const char* s);
+
+int kvsnprintf(char* out, size_t out_size, const char* fmt, va_list ap);
+int ksnprintf(char* out, size_t out_size, const char* fmt, ...);
+
+void kprintf(const char* fmt, ...);
+
+#endif
index 98fb466ca23eb18573a614de4a00a4eef0c3dc7d..09992720dafaef6c5a23803f7b8bbd5c7ab0e921 100644 (file)
@@ -6,6 +6,7 @@
 #include "syscall.h"
 #include "timer.h"
 #include "uart_console.h"
+#include "console.h"
 #include "uaccess.h"
 #include "vga_console.h"
 #include "vmm.h"
@@ -72,7 +73,8 @@ int arch_platform_setup(const struct boot_info* bi) {
 
     vga_init();
     vga_set_color(0x0A, 0x00);
-    vga_print("[AdrOS] Kernel Initialized (VGA).\n");
+    console_enable_vga(1);
+    kprintf("[AdrOS] Kernel Initialized (VGA).\n");
 
     syscall_init();
     keyboard_init();
diff --git a/src/kernel/console.c b/src/kernel/console.c
new file mode 100644 (file)
index 0000000..089211a
--- /dev/null
@@ -0,0 +1,192 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#include "console.h"
+
+#include "spinlock.h"
+#include "uart_console.h"
+#include "vga_console.h"
+
+static spinlock_t g_console_lock = {0};
+static int g_console_uart_enabled = 1;
+static int g_console_vga_enabled = 0;
+
+void console_init(void) {
+    spinlock_init(&g_console_lock);
+    g_console_uart_enabled = 1;
+    g_console_vga_enabled = 0;
+}
+
+void console_enable_uart(int enabled) {
+    uintptr_t flags = spin_lock_irqsave(&g_console_lock);
+    g_console_uart_enabled = enabled ? 1 : 0;
+    spin_unlock_irqrestore(&g_console_lock, flags);
+}
+
+void console_enable_vga(int enabled) {
+    uintptr_t flags = spin_lock_irqsave(&g_console_lock);
+    g_console_vga_enabled = enabled ? 1 : 0;
+    spin_unlock_irqrestore(&g_console_lock, flags);
+}
+
+void console_write(const char* s) {
+    if (!s) return;
+
+    uintptr_t flags = spin_lock_irqsave(&g_console_lock);
+
+    if (g_console_uart_enabled) {
+        uart_print(s);
+    }
+    if (g_console_vga_enabled) {
+        vga_print(s);
+    }
+
+    spin_unlock_irqrestore(&g_console_lock, flags);
+}
+
+static void out_char(char** dst, size_t* rem, int* total, char c) {
+    (*total)++;
+    if (*rem == 0) return;
+    **dst = c;
+    (*dst)++;
+    (*rem)--;
+}
+
+static void out_str(char** dst, size_t* rem, int* total, const char* s) {
+    if (!s) s = "(null)";
+    for (size_t i = 0; s[i] != 0; i++) {
+        out_char(dst, rem, total, s[i]);
+    }
+}
+
+static void out_uint_base_u32(char** dst, size_t* rem, int* total, uint32_t v, unsigned base, int upper) {
+    char tmp[32];
+    size_t n = 0;
+
+    if (base < 2 || base > 16) base = 10;
+
+    if (v == 0) {
+        tmp[n++] = '0';
+    } else {
+        while (v != 0 && n < sizeof(tmp)) {
+            unsigned d = (unsigned)(v % (uint32_t)base);
+            if (d < 10) tmp[n++] = (char)('0' + d);
+            else tmp[n++] = (char)((upper ? 'A' : 'a') + (d - 10));
+            v /= (uint32_t)base;
+        }
+    }
+
+    while (n > 0) {
+        out_char(dst, rem, total, tmp[--n]);
+    }
+}
+
+static void out_uint_hex_fixed_u32(char** dst, size_t* rem, int* total, uint32_t v, int digits, int upper) {
+    const char* hex = upper ? "0123456789ABCDEF" : "0123456789abcdef";
+    for (int i = digits - 1; i >= 0; i--) {
+        unsigned nibble = (unsigned)((v >> (i * 4)) & 0xF);
+        out_char(dst, rem, total, hex[nibble]);
+    }
+}
+
+static void out_int_i32(char** dst, size_t* rem, int* total, int32_t v) {
+    if (v < 0) {
+        out_char(dst, rem, total, '-');
+        out_uint_base_u32(dst, rem, total, (uint32_t)(-v), 10, 0);
+    } else {
+        out_uint_base_u32(dst, rem, total, (uint32_t)v, 10, 0);
+    }
+}
+
+int kvsnprintf(char* out, size_t out_size, const char* fmt, va_list ap) {
+    if (!out || out_size == 0) return 0;
+    if (!fmt) {
+        out[0] = 0;
+        return 0;
+    }
+
+    char* dst = out;
+    size_t rem = out_size - 1;
+    int total = 0;
+
+    for (size_t i = 0; fmt[i] != 0; i++) {
+        char c = fmt[i];
+        if (c != '%') {
+            out_char(&dst, &rem, &total, c);
+            continue;
+        }
+
+        char spec = fmt[++i];
+        if (spec == 0) break;
+
+        switch (spec) {
+            case '%':
+                out_char(&dst, &rem, &total, '%');
+                break;
+            case 'c': {
+                int v = va_arg(ap, int);
+                out_char(&dst, &rem, &total, (char)v);
+                break;
+            }
+            case 's': {
+                const char* s = va_arg(ap, const char*);
+                out_str(&dst, &rem, &total, s);
+                break;
+            }
+            case 'd':
+            case 'i': {
+                int v = va_arg(ap, int);
+                out_int_i32(&dst, &rem, &total, (int32_t)v);
+                break;
+            }
+            case 'u': {
+                unsigned v = va_arg(ap, unsigned);
+                out_uint_base_u32(&dst, &rem, &total, (uint32_t)v, 10, 0);
+                break;
+            }
+            case 'x': {
+                unsigned v = va_arg(ap, unsigned);
+                out_uint_base_u32(&dst, &rem, &total, (uint32_t)v, 16, 0);
+                break;
+            }
+            case 'X': {
+                unsigned v = va_arg(ap, unsigned);
+                out_uint_base_u32(&dst, &rem, &total, (uint32_t)v, 16, 1);
+                break;
+            }
+            case 'p': {
+                uintptr_t v = (uintptr_t)va_arg(ap, void*);
+                out_str(&dst, &rem, &total, "0x");
+                out_uint_hex_fixed_u32(&dst, &rem, &total, (uint32_t)v, 8, 1);
+                break;
+            }
+            default:
+                out_char(&dst, &rem, &total, '%');
+                out_char(&dst, &rem, &total, spec);
+                break;
+        }
+    }
+
+    *dst = 0;
+    return total;
+}
+
+int ksnprintf(char* out, size_t out_size, const char* fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    int r = kvsnprintf(out, out_size, fmt, ap);
+    va_end(ap);
+    return r;
+}
+
+void kprintf(const char* fmt, ...) {
+    char buf[512];
+
+    va_list ap;
+    va_start(ap, fmt);
+    (void)kvsnprintf(buf, sizeof(buf), fmt, ap);
+    va_end(ap);
+
+    console_write(buf);
+}
index cf477f3381046856f353d88fd46e081b1c1968c3..a89b5606365d513ef893bd72997a507e7511e7fd 100644 (file)
@@ -1,5 +1,6 @@
 #include <stdint.h>
 #include <stddef.h>
+#include "console.h"
 #include "vga_console.h"
 #include "uart_console.h"
 #include "pmm.h"
  * Arguments are passed from boot.S (architecture specific)
  */
 void kernel_main(const struct boot_info* bi) {
-    
-    uart_print("[AdrOS] Initializing PMM...\n");
+    console_init();
+
+    kprintf("[AdrOS] Initializing PMM...\n");
     
     // 2. Initialize Physical Memory Manager
     pmm_init((void*)(bi ? bi->arch_boot_info : 0));
     
     // 3. Initialize Virtual Memory Manager
-    uart_print("[AdrOS] Initializing VMM...\n");
+    kprintf("[AdrOS] Initializing VMM...\n");
     if (arch_platform_setup(bi) < 0) {
-        uart_print("[WARN] VMM/IDT/Sched not implemented for this architecture yet.\n");
+        kprintf("[WARN] VMM/IDT/Sched not implemented for this architecture yet.\n");
         goto done;
     }
 
@@ -51,7 +53,7 @@ void kernel_main(const struct boot_info* bi) {
     kheap_init();
     
     // 7. Initialize Multitasking
-    uart_print("[AdrOS] Initializing Scheduler...\n");
+    kprintf("[AdrOS] Initializing Scheduler...\n");
     process_init();
     
     // 8. Start Timer (Preemption!) - 50Hz
@@ -67,7 +69,7 @@ void kernel_main(const struct boot_info* bi) {
     }
     
 done:
-    uart_print("Welcome to AdrOS (x86/ARM/RISC-V/MIPS)!\n");
+    kprintf("Welcome to AdrOS (x86/ARM/RISC-V/MIPS)!\n");
 
     // Infinite loop acting as Idle Task
     for(;;) {