diff options
| author | Arseney300 <Arseney300@gmail.com> | 2026-04-23 17:02:05 +0700 |
|---|---|---|
| committer | Arseney300 <Arseney300@gmail.com> | 2026-04-23 17:02:05 +0700 |
| commit | e935c3afba9b3a492ad804726fa0fd97d437d8f5 (patch) | |
| tree | c8c26fe36ed4db1ffec4dab5f5bf3b489c064a07 /kernel | |
| parent | 496246c92dabe6757480147016490ea6ae43bb66 (diff) | |
WIP: add driver objectsWIP/add_driver_obj
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/Makefile | 6 | ||||
| -rw-r--r-- | kernel/drivers/char/pl011.cpp | 83 | ||||
| -rw-r--r-- | kernel/drivers/char/uart_16550.cpp | 85 | ||||
| -rw-r--r-- | kernel/drivers/console/framebuffer.cpp | 328 | ||||
| -rw-r--r-- | kernel/drivers/driver_registry.cpp | 55 | ||||
| -rw-r--r-- | kernel/include/kernel/console_driver.h | 58 | ||||
| -rw-r--r-- | kernel/include/kernel/device.h | 52 | ||||
| -rw-r--r-- | kernel/include/kernel/driver.h | 46 | ||||
| -rw-r--r-- | kernel/include/kernel/driver_list.h | 34 | ||||
| -rw-r--r-- | kernel/include/kernel/early_device.h | 35 | ||||
| -rw-r--r-- | kernel/include/kernel/early_driver.h | 40 | ||||
| -rw-r--r-- | kernel/include/kernel/placement_new.h | 4 | ||||
| -rw-r--r-- | kernel/include/kernel/platform_bus.h | 22 | ||||
| -rw-r--r-- | kernel/lib/framebuffer.cpp | 316 |
14 files changed, 880 insertions, 284 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index 40f081e..c3634e0 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -28,6 +28,10 @@ LIB_SRC := $(wildcard lib/*.cpp) # ── Firmware subsystems (both compile on all arches; unused one stays dormant) ── FIRMWARE_SRC := $(wildcard firmware/acpi/*.cpp) $(wildcard firmware/dt/*.cpp) +# ── Driver framework (always compiled) ───────────────────────────────────── +# TODO: fix that +DRV_FRAMEWORK_SRC := $(wildcard drivers/driver_registry.cpp) + # ── Conditionally-compiled sources (from .config) ─────────────────────────── # TODO: change it to Driver Makefiles DRV_SRC := @@ -72,7 +76,7 @@ endif # ── Collect all sources ───────────────────────────────────────────────────── -ALL_CPP_SRC := $(ARCH_CPP_SRC) $(CORE_SRC) $(MM_SRC) $(FIRMWARE_SRC) $(DRV_SRC) $(FS_SRC) $(LDR_SRC) $(LIB_SRC) +ALL_CPP_SRC := $(ARCH_CPP_SRC) $(CORE_SRC) $(MM_SRC) $(FIRMWARE_SRC) $(DRV_FRAMEWORK_SRC) $(DRV_SRC) $(FS_SRC) $(LDR_SRC) $(LIB_SRC) ALL_ASM_SRC := $(ARCH_ASM_SRC) ALL_CPP_OBJ := $(patsubst %.cpp,%.o,$(ALL_CPP_SRC)) diff --git a/kernel/drivers/char/pl011.cpp b/kernel/drivers/char/pl011.cpp new file mode 100644 index 0000000..7615370 --- /dev/null +++ b/kernel/drivers/char/pl011.cpp @@ -0,0 +1,83 @@ +// ============================================================================ +// drivers/char/pl011.cpp — PL011 UART console driver + device (aarch64) +// +// Stub implementation that compiles but does no real I/O yet. +// TODO: Program IBRD, FBRD, LCR_H, CR registers for actual UART output. +// ============================================================================ + +#include <kernel/console_driver.h> +#include <kernel/early_driver.h> +#include <kernel/early_device.h> +#include <kernel/platform_bus.h> + +// ── PL011Device ─────────────────────────────────────────────────────────── + +class PL011Device : public Device, public EarlyDevice<PL011Device> { +public: + explicit PL011Device(uintptr_t base_addr) : base_(base_addr) {} + + const char* name() const override { return "uart0"; } + uintptr_t base() const { return base_; } + +private: + uintptr_t base_; +}; + +// ── PL011Console driver ────────────────────────────────────────────────── + +class PL011Console : public ConsoleDriver, + public EarlyDriver<PL011Console> { +public: + PL011Console() = default; + + const char* name() const override { return "pl011-uart"; } + + bool init() override { + auto* dev = static_cast<PL011Device*>(device()); + base_ = dev->base(); + + // TODO: Configure UART registers at base_: + // UARTIBRD (offset 0x24) — integer baud rate divisor + // UARTFBRD (offset 0x28) — fractional baud rate divisor + // UARTLCR_H (offset 0x2C) — line control (8N1, FIFO enable) + // UARTCR (offset 0x30) — control register (TX enable, UART enable) + initialized_ = true; + return true; + } + + void shutdown() override { + initialized_ = false; + } + + void putchar(char c) override { + if (!initialized_) return; + // TODO: while (*(volatile uint32_t*)(base_ + 0x18) & (1 << 5)) {} + // *(volatile uint32_t*)(base_ + 0x00) = c; + (void)c; + } + + void clear() override { + // UART has no screen to clear + } + +private: + uintptr_t base_ = 0; + bool initialized_ = false; +}; + +// ── Driver init function ────────────────────────────────────────────────── + +namespace console { + +void init_pl011(uintptr_t base_addr) { + auto* dev = PL011Device::create(base_addr); + platform::bus().add_device(dev); + + auto* drv = PL011Console::create(); + drv->bind(dev); + drv->init(); + + console::register_driver(drv); +} + +} // namespace console diff --git a/kernel/drivers/char/uart_16550.cpp b/kernel/drivers/char/uart_16550.cpp new file mode 100644 index 0000000..a85b5e7 --- /dev/null +++ b/kernel/drivers/char/uart_16550.cpp @@ -0,0 +1,85 @@ +// ============================================================================ +// drivers/char/uart_16550.cpp — 16550 UART console driver + device (x86_64) +// +// Stub implementation that compiles but does no real I/O yet. +// TODO: Program divisor latch, 8N1, FIFO, implement actual port I/O. +// ============================================================================ + +#include <kernel/console_driver.h> +#include <kernel/early_driver.h> +#include <kernel/early_device.h> +#include <kernel/platform_bus.h> + +// ── UART16550Device ─────────────────────────────────────────────────────── + +class UART16550Device : public Device, public EarlyDevice<UART16550Device> { +public: + explicit UART16550Device(uint16_t port) : port_(port) {} + + const char* name() const override { return "uart0"; } + uint16_t port() const { return port_; } + +private: + uint16_t port_; +}; + +// ── UART16550Console driver ─────────────────────────────────────────────── + +class UART16550Console : public ConsoleDriver, + public EarlyDriver<UART16550Console> { +public: + UART16550Console() = default; + + const char* name() const override { return "uart-16550"; } + + bool init() override { + auto* dev = static_cast<UART16550Device*>(device()); + port_ = dev->port(); + + // TODO: outb(port_ + 1, 0x00) — disable interrupts + // TODO: outb(port_ + 3, 0x80) — enable DLAB + // TODO: outb(port_ + 0, 0x03) — set divisor (lo) 38400 baud + // TODO: outb(port_ + 1, 0x00) — set divisor (hi) + // TODO: outb(port_ + 3, 0x03) — 8 bits, no parity, one stop + // TODO: outb(port_ + 2, 0xC7) — enable FIFO, clear, 14-byte threshold + // TODO: outb(port_ + 4, 0x0B) — IRQs enabled, RTS/DSR set + initialized_ = true; + return true; + } + + void shutdown() override { + initialized_ = false; + } + + void putchar(char c) override { + if (!initialized_) return; + // TODO: while (!(inb(port_ + 5) & 0x20)) {} — wait for THR empty + // TODO: outb(port_, c) + (void)c; + } + + void clear() override { + // UART has no screen to clear + } + +private: + uint16_t port_ = 0; + bool initialized_ = false; +}; + +// ── Driver init function ────────────────────────────────────────────────── + +namespace console { + +void init_uart_16550(uint16_t port) { + auto* dev = UART16550Device::create(port); + platform::bus().add_device(dev); + + auto* drv = UART16550Console::create(); + drv->bind(dev); + drv->init(); + + console::register_driver(drv); +} + +} // namespace console diff --git a/kernel/drivers/console/framebuffer.cpp b/kernel/drivers/console/framebuffer.cpp new file mode 100644 index 0000000..e7f0577 --- /dev/null +++ b/kernel/drivers/console/framebuffer.cpp @@ -0,0 +1,328 @@ +// ============================================================================ +// drivers/console/framebuffer.cpp — Framebuffer console driver + device +// +// FramebufferDevice describes the GOP framebuffer hardware (base address, +// resolution, pixel format). FramebufferConsole is the driver that renders +// text to it using a built-in 8x16 VGA bitmap font. +// +// Both are early-allocated (static storage, no heap). +// ============================================================================ + +#include <kernel/console_driver.h> +#include <kernel/early_driver.h> +#include <kernel/early_device.h> +#include <kernel/platform_bus.h> +#include <boot/boot_info.h> + +// ── Minimal 8x16 bitmap font (ASCII 32-126) ────────────────────────────── + +static constexpr int FONT_FIRST = 32; +static constexpr int FONT_LAST = 126; + +// clang-format off +static const uint8_t g_font[][16] = { + // 32: space + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + // 33: ! + {0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, + // 34: " + {0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + // 35: # + {0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, + // 36: $ + {0x00,0x10,0x10,0x7C,0xD6,0xD0,0x7C,0x16,0xD6,0x7C,0x10,0x10,0x00,0x00,0x00,0x00}, + // 37: % + {0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00}, + // 38: & + {0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}, + // 39: ' + {0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + // 40: ( + {0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00}, + // 41: ) + {0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00}, + // 42: * + {0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00}, + // 43: + + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00}, + // 44: , + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00}, + // 45: - + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + // 46: . + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, + // 47: / + {0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00}, + // 48-57: 0-9 + {0x00,0x00,0x7C,0xC6,0xC6,0xCE,0xDE,0xF6,0xE6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00}, + // 58: : + {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, + // 59: ; + {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00}, + // 60: < + {0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00}, + // 61: = + {0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + // 62: > + {0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00}, + // 63: ? + {0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, + // 64: @ + {0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0xC0,0x7C,0x00,0x00,0x00,0x00}, + // 65-90: A-Z + {0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00}, + {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00}, + // 91: [ + {0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00}, + // 92: backslash + {0x00,0x00,0x00,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00,0x00,0x00,0x00,0x00}, + // 93: ] + {0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00}, + // 94: ^ + {0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + // 95: _ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00}, + // 96: ` + {0x00,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + // 97-122: a-z + {0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}, + {0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0xCC,0x78,0x00}, + {0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00}, + {0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0xEC,0xFE,0xD6,0xD6,0xD6,0xD6,0xC6,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00}, + {0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00}, + {0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00}, + // 123: { + {0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00}, + // 124: | + {0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00}, + // 125: } + {0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00}, + // 126: ~ + {0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +}; +// clang-format on + +// ── FramebufferDevice ───────────────────────────────────────────────────── + +class FramebufferDevice : public Device, public EarlyDevice<FramebufferDevice> { +public: + explicit FramebufferDevice(const FramebufferInfo& fb) + : base_(fb.base), width_(fb.width), height_(fb.height) + , pitch_(fb.pitch), format_(fb.format) + {} + + const char* name() const override { return "framebuffer0"; } + + uint64_t base() const { return base_; } + uint32_t width() const { return width_; } + uint32_t height() const { return height_; } + uint32_t pitch() const { return pitch_; } + PixelFormat format() const { return format_; } + +private: + uint64_t base_; + uint32_t width_; + uint32_t height_; + uint32_t pitch_; + PixelFormat format_; +}; + +// ── FramebufferConsole driver ───────────────────────────────────────────── + +class FramebufferConsole : public ConsoleDriver, + public EarlyDriver<FramebufferConsole> { +public: + FramebufferConsole() = default; + + const char* name() const override { return "framebuffer-console"; } + + bool init() override { + auto* dev = static_cast<FramebufferDevice*>(device()); + fb_ = reinterpret_cast<uint32_t*>(dev->base()); + width_ = dev->width(); + height_ = dev->height(); + pitch_ = dev->pitch(); + is_bgr_ = (dev->format() == PixelFormat::BGR); + clear(); + return true; + } + + void shutdown() override {} + + void putchar(char c) override { + uint32_t max_cols = width_ / CHAR_W; + uint32_t max_rows = height_ / CHAR_H; + + if (c == '\n') { + col_ = 0; + row_++; + } else if (c == '\r') { + col_ = 0; + } else if (c == '\t') { + col_ = (col_ + 4) & ~3u; + } else { + render_char(col_, row_, c); + col_++; + } + + if (col_ >= max_cols) { + col_ = 0; + row_++; + } + + if (row_ >= max_rows) { + scroll(); + row_ = max_rows - 1; + } + } + + void clear() override { + for (uint32_t y = 0; y < height_; y++) { + for (uint32_t x = 0; x < width_; x++) { + put_pixel(x, y, BG_COLOR); + } + } + col_ = 0; + row_ = 0; + } + +private: + uint32_t* fb_ = nullptr; + uint32_t width_ = 0; + uint32_t height_ = 0; + uint32_t pitch_ = 0; + bool is_bgr_ = false; + uint32_t col_ = 0; + uint32_t row_ = 0; + + static constexpr uint32_t CHAR_W = 8; + static constexpr uint32_t CHAR_H = 16; + static constexpr uint32_t FG_COLOR = CONFIG_FBCON_FG_COLOR; + static constexpr uint32_t BG_COLOR = CONFIG_FBCON_BG_COLOR; + + void put_pixel(uint32_t x, uint32_t y, uint32_t rgb) { + if (x >= width_ || y >= height_) return; + + uint32_t color; + if (is_bgr_) { + color = ((rgb & 0xFF) << 16) | (rgb & 0xFF00) | ((rgb >> 16) & 0xFF); + } else { + color = rgb; + } + + auto* row = reinterpret_cast<uint32_t*>( + reinterpret_cast<uint8_t*>(fb_) + y * pitch_); + row[x] = color; + } + + void scroll() { + uint32_t row_bytes = pitch_; + uint32_t shift = CHAR_H * row_bytes; + uint32_t total = height_ * row_bytes; + + auto* fb = reinterpret_cast<uint8_t*>(fb_); + + for (uint32_t i = 0; i < total - shift; i++) { + fb[i] = fb[i + shift]; + } + for (uint32_t i = total - shift; i < total; i++) { + fb[i] = 0; + } + uint32_t start_y = height_ - CHAR_H; + for (uint32_t y = start_y; y < height_; y++) { + for (uint32_t x = 0; x < width_; x++) { + put_pixel(x, y, BG_COLOR); + } + } + } + + void render_char(uint32_t col, uint32_t row, char c) { + int idx = static_cast<int>(c) - FONT_FIRST; + if (idx < 0 || idx > (FONT_LAST - FONT_FIRST)) idx = 0; + + uint32_t px = col * CHAR_W; + uint32_t py = row * CHAR_H; + + for (uint32_t y = 0; y < CHAR_H; y++) { + uint8_t bits = g_font[idx][y]; + for (uint32_t x = 0; x < CHAR_W; x++) { + uint32_t color = (bits & (0x80 >> x)) ? FG_COLOR : BG_COLOR; + put_pixel(px + x, py + y, color); + } + } + } +}; + +// ── Driver init function ────────────────────────────────────────────────── + +namespace console { + +void init_framebuffer(const FramebufferInfo& fb) { + // Create device on the platform bus + auto* dev = FramebufferDevice::create(fb); + platform::bus().add_device(dev); + + // Create driver and bind to device + auto* drv = FramebufferConsole::create(); + drv->bind(dev); + drv->init(); + + // Register as active console + console::register_driver(drv); + console::set_active(drv); +} + +} // namespace console diff --git a/kernel/drivers/driver_registry.cpp b/kernel/drivers/driver_registry.cpp new file mode 100644 index 0000000..43b2b5a --- /dev/null +++ b/kernel/drivers/driver_registry.cpp @@ -0,0 +1,55 @@ +// ============================================================================ +// drivers/driver_registry.cpp — Driver/device registry globals +// +// Provides storage for per-category driver lists, the active console +// pointer, and the platform bus singleton. Always compiled. +// ============================================================================ + +#include <kernel/console_driver.h> +#include <kernel/platform_bus.h> + +// ── ConsoleDriver default write implementation ──────────────────────────── + +void ConsoleDriver::write(const char* s, size_t len) { + for (size_t i = 0; i < len; ++i) { + putchar(s[i]); + } +} + +// ── Console registry ────────────────────────────────────────────────────── + +static DriverList<ConsoleDriver> g_console_drivers; +static ConsoleDriver* g_active_console = nullptr; + +namespace console { + +void register_driver(ConsoleDriver* driver) { + g_console_drivers.add(driver); +} + +void set_active(ConsoleDriver* driver) { + g_active_console = driver; +} + +ConsoleDriver* active() { + return g_active_console; +} + +DriverList<ConsoleDriver>& drivers() { + return g_console_drivers; +} + +} // namespace console + +// ── Platform bus (lazy singleton) ───────────────────────────────────────── + +namespace platform { + +Bus& bus() { + if (!PlatformBus::instance()) { + PlatformBus::create(); + } + return *PlatformBus::instance(); +} + +} // namespace platform diff --git a/kernel/include/kernel/console_driver.h b/kernel/include/kernel/console_driver.h new file mode 100644 index 0000000..f34c4e0 --- /dev/null +++ b/kernel/include/kernel/console_driver.h @@ -0,0 +1,58 @@ +#pragma once + +// ============================================================================ +// kernel/console_driver.h — Console driver category + registry +// +// ConsoleDriver is the category base for all text output devices +// (framebuffer, UART, etc.). The console:: namespace provides the global +// registry and active-console tracking. +// ============================================================================ + +#include <stdint.h> +#include <stddef.h> +#include <kernel/driver.h> +#include <kernel/driver_list.h> + +struct FramebufferInfo; // forward declaration (defined in boot/boot_info.h) + +class ConsoleDriver : public Driver { +public: + // Write a single character (handles newline, cursor, scrolling). + virtual void putchar(char c) = 0; + + // Write a buffer of characters. Default: loops over putchar(). + virtual void write(const char* s, size_t len); + + // Clear the screen / output buffer. + virtual void clear() = 0; +}; + +namespace console { + +// Register a console driver in the global list. +void register_driver(ConsoleDriver* driver); + +// Set the active console (the one kcon:: delegates to). +void set_active(ConsoleDriver* driver); + +// Get the current active console (nullptr before any console is initialized). +ConsoleDriver* active(); + +// Get the driver list for enumeration. +DriverList<ConsoleDriver>& drivers(); + +// ── Per-driver init functions (guarded by config) ───────────────────────── + +#ifdef CONFIG_DRIVER_FBCON +void init_framebuffer(const FramebufferInfo& fb); +#endif + +#ifdef CONFIG_DRIVER_UART_16550 +void init_uart_16550(uint16_t port = 0x3F8); +#endif + +#ifdef CONFIG_DRIVER_PL011_UART +void init_pl011(uintptr_t base_addr = 0x09000000); +#endif + +} // namespace console diff --git a/kernel/include/kernel/device.h b/kernel/include/kernel/device.h new file mode 100644 index 0000000..222ff9e --- /dev/null +++ b/kernel/include/kernel/device.h @@ -0,0 +1,52 @@ +#pragma once + +// ============================================================================ +// kernel/device.h — Device and Bus base classes +// +// A Device represents a piece of hardware. Devices form a tree via +// intrusive parent-child pointers (no heap needed). Each Device can be +// bound to a Driver that knows how to operate it. +// +// A Bus is a Device that can have child devices. It serves as a grouping +// point for device enumeration and driver matching (future: PCI, DT). +// ============================================================================ + +#include <stdint.h> + +class Driver; + +class Device { +public: + virtual ~Device() = default; + + virtual const char* name() const = 0; + + // ── Hierarchy ───────────────────────────────────────────────────────── + Device* parent() const { return parent_; } + Device* first_child() const { return first_child_; } + Device* next_sibling() const { return next_sibling_; } + + void add_child(Device* child) { + child->parent_ = this; + child->next_sibling_ = first_child_; + first_child_ = child; + } + + // ── Driver binding ──────────────────────────────────────────────────── + Driver* driver() const { return driver_; } + void set_driver(Driver* drv) { driver_ = drv; } + +protected: + Device* parent_ = nullptr; + Device* first_child_ = nullptr; + Device* next_sibling_ = nullptr; + Driver* driver_ = nullptr; +}; + +// ── Bus — a Device that groups child devices ────────────────────────────── +// Future: enumerate() discovers children, match() pairs devices with drivers. + +class Bus : public Device { +public: + void add_device(Device* dev) { add_child(dev); } +}; diff --git a/kernel/include/kernel/driver.h b/kernel/include/kernel/driver.h new file mode 100644 index 0000000..564590b --- /dev/null +++ b/kernel/include/kernel/driver.h @@ -0,0 +1,46 @@ +#pragma once + +// ============================================================================ +// kernel/driver.h - Base driver class +// +// Abstract root of the driver hierarchy. Every driver inherits from this. +// Registration uses an intrusive singly-linked list (next_ pointer). +// A driver can be bound to a Device via bind(). +// ============================================================================ + +#include <stdint.h> +#include <kernel/device.h> + +template <typename T> +class DriverList; + +class Driver { +public: + virtual ~Driver() = default; + + // Human-readable name, e.g. "framebuffer-console", "uart-16550" + virtual const char* name() const = 0; + + // Initialize driver hardware/state. Returns true on success. + // Called after bind() — device() is available for reading hw info. + virtual bool init() = 0; + + // Shut down driver (release resources, disable hardware). + virtual void shutdown() = 0; + + // ── Device binding ──────────────────────────────────────────────────── + // Links this driver to a device. Sets bidirectional pointers. + void bind(Device* dev) { + device_ = dev; + dev->set_driver(this); + } + + Device* device() const { return device_; } + +protected: + Driver* next_ = nullptr; + Device* device_ = nullptr; + + template <typename T> + friend class DriverList; +}; diff --git a/kernel/include/kernel/driver_list.h b/kernel/include/kernel/driver_list.h new file mode 100644 index 0000000..1ba9ab2 --- /dev/null +++ b/kernel/include/kernel/driver_list.h @@ -0,0 +1,34 @@ +#pragma once + +// ============================================================================ +// kernel/driver_list.h — Typed intrusive singly-linked list for drivers +// +// Each driver category (console, block, etc.) maintains its own DriverList. +// Insertion is O(1) prepend. No heap allocation — the list node is the +// driver's own next_ pointer inherited from Driver. +// ============================================================================ + +#include <kernel/driver.h> + +template <typename T> +class DriverList { +public: + // Prepend a driver to the list. + void add(T* driver) { + driver->next_ = head_; + head_ = driver; + } + + // Iterate all drivers. fn(T*) returns true to stop early. + template <typename Fn> + void for_each(Fn fn) const { + for (auto* d = head_; d != nullptr; d = static_cast<T*>(d->next_)) { + if (fn(d)) return; + } + } + + T* head() const { return head_; } + +private: + T* head_ = nullptr; +}; diff --git a/kernel/include/kernel/early_device.h b/kernel/include/kernel/early_device.h new file mode 100644 index 0000000..5ddec7b --- /dev/null +++ b/kernel/include/kernel/early_device.h @@ -0,0 +1,35 @@ +#pragma once + +// ============================================================================ +// kernel/early_device.h — CRTP mixin for pre-heap device allocation +// +// Same pattern as EarlyDriver<T>, but for Device subclasses. Provides +// static storage for exactly one instance of the derived device type. +// +// Usage: +// class MyDevice : public Device, public EarlyDevice<MyDevice> { }; +// auto* dev = MyDevice::create(args...); +// MyDevice::instance(); +// ============================================================================ + +#include <stdint.h> +#include <stddef.h> +#include <kernel/placement_new.h> + +template <typename Derived> +class EarlyDevice { +public: + template <typename... Args> + static Derived* create(Args&&... args) { + alignas(Derived) static char storage[sizeof(Derived)]; + instance_ = new (storage) Derived(static_cast<Args&&>(args)...); + return instance_; + } + + static Derived* instance() { + return instance_; + } + +private: + static inline Derived* instance_ = nullptr; +}; diff --git a/kernel/include/kernel/early_driver.h b/kernel/include/kernel/early_driver.h new file mode 100644 index 0000000..ff1b3b9 --- /dev/null +++ b/kernel/include/kernel/early_driver.h @@ -0,0 +1,40 @@ +#pragma once + +// ============================================================================ +// kernel/early_driver.h — CRTP mixin for pre-heap driver allocation +// +// Early drivers (framebuffer console, serial UART) must work before kmalloc +// exists. This template provides static storage for exactly one instance of +// the derived driver, constructed via placement new. +// +// Usage: +// class MyDriver : public SomeCategory, public EarlyDriver<MyDriver> { }; +// auto* drv = MyDriver::create(args...); // placement new into BSS +// MyDriver::instance(); // get the singleton +// ============================================================================ + +#include <stdint.h> +#include <stddef.h> +#include <kernel/placement_new.h> + +template <typename Derived> +class EarlyDriver { +public: + // Construct the driver in static storage. Call exactly once. + // sizeof(Derived) is evaluated here, not at class definition time, + // so Derived is guaranteed to be complete. + template <typename... Args> + static Derived* create(Args&&... args) { + alignas(Derived) static char storage[sizeof(Derived)]; + instance_ = new (storage) Derived(static_cast<Args&&>(args)...); + return instance_; + } + + // Returns the instance, or nullptr if create() hasn't been called. + static Derived* instance() { + return instance_; + } + +private: + static inline Derived* instance_ = nullptr; +}; diff --git a/kernel/include/kernel/placement_new.h b/kernel/include/kernel/placement_new.h new file mode 100644 index 0000000..6f7f1f3 --- /dev/null +++ b/kernel/include/kernel/placement_new.h @@ -0,0 +1,4 @@ +#pragma once + +// Placement new for freestanding C++ (no <new> header available). +inline void* operator new(size_t, void* ptr) noexcept { return ptr; } diff --git a/kernel/include/kernel/platform_bus.h b/kernel/include/kernel/platform_bus.h new file mode 100644 index 0000000..8561ca6 --- /dev/null +++ b/kernel/include/kernel/platform_bus.h @@ -0,0 +1,22 @@ +#pragma once + +// ============================================================================ +// kernel/platform_bus.h — Platform bus for fixed-address devices +// +// The PlatformBus is the root of the device hierarchy. Non-discoverable +// devices (framebuffer, UART at fixed addresses) are registered here. +// Future buses (PCI, device-tree) will be added as siblings or children. +// ============================================================================ + +#include <kernel/device.h> +#include <kernel/early_device.h> + +class PlatformBus : public Bus, public EarlyDevice<PlatformBus> { +public: + const char* name() const override { return "platform"; } +}; + +// Lazy-initialized singleton accessor for the platform bus. +namespace platform { + Bus& bus(); +} // namespace platform diff --git a/kernel/lib/framebuffer.cpp b/kernel/lib/framebuffer.cpp index 476abaa..4cd163d 100644 --- a/kernel/lib/framebuffer.cpp +++ b/kernel/lib/framebuffer.cpp @@ -1,297 +1,37 @@ // ============================================================================ -// lib/framebuffer.cpp - Early kernel framebuffer console +// lib/framebuffer.cpp — kcon:: delegation layer // -// Renders text directly to the linear framebuffer using a minimal -// built-in 8x16 bitmap font (PC VGA style, ASCII 32-126). +// The kcon:: namespace preserves the original console API. All rendering +// is now handled by whichever ConsoleDriver is active (typically +// FramebufferConsole via the driver framework). Formatting functions +// (put_hex, put_dec, kprintf) are kept here since they are pure formatters +// that call putchar/puts. // ============================================================================ #include <kernel/kprint.h> +#include <kernel/console_driver.h> #include <stdarg.h> namespace kcon { -// ── Character cell dimensions ────────────────────────────────────────────── - -static constexpr uint32_t CHAR_W = 8; // Font glyph width in pixels -static constexpr uint32_t CHAR_H = 16; // Font glyph height in pixels -static constexpr uint32_t TAB_WIDTH = 4; // Tab stop width in character cells - -// ── Colors (0x00RRGGBB) ──────────────────────────────────────────────────── - -static constexpr uint32_t FG_COLOR = CONFIG_FBCON_FG_COLOR; // Light grey -static constexpr uint32_t BG_COLOR = CONFIG_FBCON_BG_COLOR; // Dark blue - -// ── Console state ────────────────────────────────────────────────────────── -// -// All mutable state lives in one struct so callers can reason about it as -// a unit and we avoid scattered bare globals. -#pragma message("when i add drivers abstract, move it to another console interface and use framebuffer as driver") - -struct Console { -public: - uint32_t* fb = nullptr; // Framebuffer base (as 32-bit pixels) - uint32_t width = 0; // Pixels per row - uint32_t height = 0; // Rows in pixels - uint32_t pitch = 0; // Bytes per scanline (>= width * 4) - uint32_t col = 0; // Cursor column in character cells - uint32_t row = 0; // Cursor row in character cells - bool is_bgr = false; - - // C++23 multi-dimensional subscript: direct reference to pixel (x, y). - // pitch is in bytes; each pixel is 4 bytes. No bounds checking — callers - // must validate coordinates before calling (put_pixel does this). - [[nodiscard]] uint32_t& operator[](uint32_t x, uint32_t y) noexcept { - auto* row_ptr = reinterpret_cast<uint32_t*>( - reinterpret_cast<uintptr_t>(fb) + static_cast<uintptr_t>(y) * pitch); - return row_ptr[x]; - } -}; - -static Console g_con{}; - -// ── Minimal 8x16 bitmap font (ASCII 32–126) ─────────────────────────────── -// Each character is 16 bytes (one byte per row, 8 pixels wide). -// We store a blank (space) for anything outside the range. - -// clang-format off -static const uint8_t g_font[][16] = { - // 32: space - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, - // 33: ! - {0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, - // 34: " - {0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, - // 35: # - {0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, - // 36: $ - {0x00,0x10,0x10,0x7C,0xD6,0xD0,0x7C,0x16,0xD6,0x7C,0x10,0x10,0x00,0x00,0x00,0x00}, - // 37: % - {0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00}, - // 38: & - {0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}, - // 39: ' - {0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, - // 40: ( - {0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00}, - // 41: ) - {0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00}, - // 42: * - {0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00}, - // 43: + - {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00}, - // 44: , - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00}, - // 45: - - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, - // 46: . - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, - // 47: / - {0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00}, - // 48-57: 0-9 - {0x00,0x00,0x7C,0xC6,0xC6,0xCE,0xDE,0xF6,0xE6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00}, - // 58: : - {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, - // 59: ; - {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00}, - // 60: < - {0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00}, - // 61: = - {0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, - // 62: > - {0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00}, - // 63: ? - {0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, - // 64: @ - {0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0xC0,0x7C,0x00,0x00,0x00,0x00}, - // 65-90: A-Z - {0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00}, - {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00}, - // 91: [ - {0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00}, - // 92: backslash - {0x00,0x00,0x00,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00,0x00,0x00,0x00,0x00}, - // 93: ] - {0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00}, - // 94: ^ - {0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, - // 95: _ - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00}, - // 96: ` - {0x00,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, - // 97-122: a-z - {0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}, - {0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0xCC,0x78,0x00}, - {0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00}, - {0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0xEC,0xFE,0xD6,0xD6,0xD6,0xD6,0xC6,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00}, - {0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00}, - {0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00}, - {0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00}, - // 123: { - {0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00}, - // 124: | - {0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00}, - // 125: } - {0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00}, - // 126: ~ - {0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, -}; -// clang-format on - -static constexpr int FONT_FIRST = 32; -static constexpr int FONT_LAST = 126; - -// ── Pixel helpers ────────────────────────────────────────────────────────── - -static void put_pixel(uint32_t x, uint32_t y, uint32_t rgb) noexcept { - if (x >= g_con.width || y >= g_con.height) return; - - // Swap R and B channels if the framebuffer uses BGR layout. - const uint32_t color = g_con.is_bgr - ? ((rgb & 0xFFu) << 16) | (rgb & 0xFF00u) | ((rgb >> 16) & 0xFFu) - : rgb; - - g_con[x, y] = color; // C++23 multi-dimensional subscript -} - -// ── Scroll the screen up by one character row ────────────────────────────── - -static void scroll() noexcept { - const uint32_t shift = CHAR_H * g_con.pitch; - const uint32_t total = g_con.height * g_con.pitch; - auto* const fb_bytes = reinterpret_cast<uint8_t*>(g_con.fb); - - // Shift everything up by CHAR_H rows (raw byte memmove equivalent). - for (uint32_t i = 0; i < total - shift; ++i) - fb_bytes[i] = fb_bytes[i + shift]; - - // Fill the newly exposed bottom rows with the background color. - for (uint32_t row = g_con.height - CHAR_H; row < g_con.height; ++row) - for (uint32_t col = 0; col < g_con.width; ++col) - put_pixel(col, row, BG_COLOR); -} - -// ── Render a glyph at character-cell position (col, row) ────────────────── - -static void render_char(uint32_t col, uint32_t row, char c) noexcept { - // Treat char as unsigned to avoid negative indices for high-ASCII. - int idx = static_cast<int>(static_cast<unsigned char>(c)) - FONT_FIRST; - if (idx < 0 || idx > (FONT_LAST - FONT_FIRST)) idx = 0; // fall back to space - - const uint32_t px = col * CHAR_W; - const uint32_t py = row * CHAR_H; - - for (uint32_t y = 0; y < CHAR_H; ++y) { - const uint8_t bits = g_font[idx][y]; - for (uint32_t x = 0; x < CHAR_W; ++x) { - const uint32_t color = (bits & (0x80u >> x)) ? FG_COLOR : BG_COLOR; - put_pixel(px + x, py + y, color); - } - } -} - -// ── Public API ───────────────────────────────────────────────────────────── +// ── Lifecycle ───────────────────────────────────────────────────────────── void init(const FramebufferInfo& fb) { - g_con.fb = reinterpret_cast<uint32_t*>(fb.base); - g_con.width = fb.width; - g_con.height = fb.height; - g_con.pitch = fb.pitch; - g_con.is_bgr = (fb.format == PixelFormat::BGR); - g_con.col = 0; - g_con.row = 0; - clear(); +#ifdef CONFIG_DRIVER_FBCON + console::init_framebuffer(fb); +#endif + (void)fb; } -void clear() { - for (uint32_t y = 0; y < g_con.height; ++y) - for (uint32_t x = 0; x < g_con.width; ++x) - put_pixel(x, y, BG_COLOR); - g_con.col = 0; - g_con.row = 0; -} +// ── Character / string output (delegate to active console) ──────────────── void putchar(char c) { - const uint32_t max_cols = g_con.width / CHAR_W; - const uint32_t max_rows = g_con.height / CHAR_H; - - if (c == '\n') { - g_con.col = 0; - ++g_con.row; - } else if (c == '\r') { - g_con.col = 0; - } else if (c == '\t') { - // Advance to the next TAB_WIDTH-aligned column. - g_con.col = (g_con.col + TAB_WIDTH) & ~(TAB_WIDTH - 1u); - } else { - render_char(g_con.col, g_con.row, c); - ++g_con.col; - } - - if (g_con.col >= max_cols) { - g_con.col = 0; - ++g_con.row; - } - - if (g_con.row >= max_rows) { - scroll(); - g_con.row = max_rows - 1; + if (auto* con = console::active()) { + con->putchar(c); } } void puts(const char* s) { - if (!s) return; while (*s) putchar(*s++); } @@ -300,11 +40,19 @@ void println(const char* s) { putchar('\n'); } +void clear() { + if (auto* con = console::active()) { + con->clear(); + } +} + +// ── Formatting (unchanged — these only call putchar/puts) ───────────────── + void put_hex(uint64_t val) { puts("0x"); bool leading = true; for (int i = 60; i >= 0; i -= 4) { - const uint8_t nibble = static_cast<uint8_t>((val >> i) & 0xFu); + uint8_t nibble = (val >> i) & 0xF; if (nibble == 0 && leading && i > 0) continue; leading = false; putchar(nibble < 10 ? '0' + nibble : 'A' + nibble - 10); @@ -315,12 +63,12 @@ void put_hex(uint64_t val) { void put_dec(uint64_t val) { if (val == 0) { putchar('0'); return; } char buf[20]; - int len = 0; + int i = 0; while (val > 0) { - buf[len++] = static_cast<char>('0' + val % 10); + buf[i++] = '0' + (val % 10); val /= 10; } - for (int j = len - 1; j >= 0; --j) putchar(buf[j]); + for (int j = i - 1; j >= 0; j--) putchar(buf[j]); } void kprintf(const char* fmt, ...) { @@ -332,7 +80,7 @@ void kprintf(const char* fmt, ...) { putchar(*fmt++); continue; } - ++fmt; // skip '%' + fmt++; // skip '%' switch (*fmt) { case 's': { @@ -347,12 +95,14 @@ void kprintf(const char* fmt, ...) { break; } case 'u': { - put_dec(va_arg(args, uint64_t)); + uint64_t v = va_arg(args, uint64_t); + put_dec(v); break; } case 'x': case 'p': { - put_hex(va_arg(args, uint64_t)); + uint64_t v = va_arg(args, uint64_t); + put_hex(v); break; } case '%': @@ -365,7 +115,7 @@ void kprintf(const char* fmt, ...) { putchar(*fmt); break; } - ++fmt; + fmt++; } done: va_end(args); |
