diff options
Diffstat (limited to 'kernel/core/kernel.cpp')
| -rw-r--r-- | kernel/core/kernel.cpp | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/kernel/core/kernel.cpp b/kernel/core/kernel.cpp new file mode 100644 index 0000000..c2d1806 --- /dev/null +++ b/kernel/core/kernel.cpp @@ -0,0 +1,283 @@ +// ============================================================================ +// core/kernel.cpp - Kernel singleton implementation +// ============================================================================ + +#include <kernel/kernel.h> +#include <kernel/kprint.h> + +using namespace kernel; + +// ── Static instance (lives in .bss, zero-initialized) ───────────────────── + +static Kernel g_kernel; + +Kernel& kernel::GetKernel() { + return g_kernel; +} +namespace { +// ── Version string formatting ───────────────────────────────────────────── + +// TODO: move it to string lib +// Hand-rolled integer-to-string (no sprintf in freestanding) +static char* format_uint(char* buf, uint16_t val) { + if (val == 0) { + *buf++ = '0'; + return buf; + } + + char tmp[6]; + int len = 0; + while (val > 0) { + tmp[len++] = '0' + (val % 10); + val /= 10; + } + for (int i = len - 1; i >= 0; i--) { + *buf++ = tmp[i]; + } + return buf; +} + +static void build_version_string(VersionInfo& ver) { + char* p = ver.string; + char* end = ver.string + sizeof(ver.string) - 1; + + p = format_uint(p, ver.major); + if (p < end) *p++ = '.'; + p = format_uint(p, ver.minor); + if (p < end) *p++ = '.'; + p = format_uint(p, ver.patch); + + if (ver.codename && p < end) { + *p++ = '-'; + const char* s = ver.codename; + while (*s && p < end) { + *p++ = *s++; + } + } + + *p = '\0'; +} + +// ── Command line helpers ────────────────────────────────────────────────── + +extern "C" size_t strlen(const char* s); + +// Check if a word (space-delimited token) is present in the command line. +static bool cmdline_has(const char* cmdline, const char* token) { + size_t token_len = strlen(token); + const char* p = cmdline; + + while (*p) { + // Skip leading spaces + while (*p == ' ') p++; + if (!*p) break; + + // Find end of current word + const char* word = p; + while (*p && *p != ' ') p++; + size_t word_len = static_cast<size_t>(p - word); + + if (word_len == token_len) { + bool match = true; + for (size_t i = 0; i < token_len; i++) { + if (word[i] != token[i]) { match = false; break; } + } + if (match) return true; + } + } + return false; +} + +// Parse "key=<decimal>" from command line. Returns 0 if not found. +static uint64_t cmdline_get_uint(const char* cmdline, const char* key) { + size_t key_len = strlen(key); + const char* p = cmdline; + + while (*p) { + while (*p == ' ') p++; + if (!*p) break; + + // Check if current word starts with "key=" + bool prefix_match = true; + for (size_t i = 0; i < key_len && p[i]; i++) { + if (p[i] != key[i]) { prefix_match = false; break; } + } + + if (prefix_match && p[key_len] == '=') { + const char* val = p + key_len + 1; + uint64_t result = 0; + while (*val >= '0' && *val <= '9') { + result = result * 10 + (*val - '0'); + val++; + } + // Handle M/G suffixes + if (*val == 'M' || *val == 'm') result *= 1024ULL * 1024; + else if (*val == 'G' || *val == 'g') result *= 1024ULL * 1024 * 1024; + return result; + } + + // Skip to next word + while (*p && *p != ' ') p++; + } + return 0; +} + +static void copy_cmdline(char* dst, const char* src, size_t max_len) { + size_t i = 0; + for (; i < max_len - 1 && src[i]; i++) + dst[i] = src[i]; + dst[i] = '\0'; +} + +} //!namespace + +// ── Kernel::init ────────────────────────────────────────────────────────── +void Kernel::init(const BootInfo& boot_info) { + state = KernelState::Booting; + + // Version info + version.major = CONFIG_KERNEL_VERSION_MAJOR; + version.minor = CONFIG_KERNEL_VERSION_MINOR; + version.patch = CONFIG_KERNEL_VERSION_PATCH; + version.codename = CONFIG_KERNEL_VERSION_NAME; + build_version_string(version); + + // Boot parameters — parse command line if provided + if (boot_info.cmdline) { + copy_cmdline(boot_params.cmdline, boot_info.cmdline, sizeof(boot_params.cmdline)); + boot_params.verbose = cmdline_has(boot_params.cmdline, "verbose"); + boot_params.nosmp = cmdline_has(boot_params.cmdline, "nosmp"); + boot_params.noacpi = cmdline_has(boot_params.cmdline, "noacpi"); + boot_params.mem_limit = cmdline_get_uint(boot_params.cmdline, "mem"); + } + + // Log level — from boot params or compile-time config + if (boot_params.verbose) { + log_level = LogLevel::Debug; + } +#ifdef CONFIG_DEBUG_VERBOSE_BOOT //TODO: fix it + else { + log_level = LogLevel::Debug; + } +#endif + + // Framebuffer (plain struct copy) + framebuffer = boot_info.framebuffer; + + // Kernel load info + kernel_phys_base = boot_info.kernel_phys_base; + kernel_virt_base = boot_info.kernel_virt_base; + kernel_size = boot_info.kernel_size; + hhdm_base = boot_info.hhdm_base; + + // Init Firmware + //TODO: when get heap fix it + if(boot_info.rsdp_address) { + tmp_acpitable[0].Init(boot_info.rsdp_address); + acpi = &tmp_acpitable[0]; + dt = nullptr; + } + if(boot_info.fdt_address) { + tmp_devicetree[0].Init(boot_info.fdt_address); + dt = &tmp_devicetree[0]; + acpi = nullptr; + } + +} + +// ── Boot data accessors ─────────────────────────────────────────────────── +//TODO: don't forget to remove FrameBuffer +const FramebufferInfo& Kernel::GetFramebuffer() const { + return framebuffer; +} + +PhysAddr Kernel::GetKernelPhysBase() const { + return kernel_phys_base; +} + +VirtAddr Kernel::GetKernelVirtBase() const { + return kernel_virt_base; +} + +uint64_t Kernel::GetKernelSize() const { + return kernel_size; +} + +VirtAddr Kernel::GetHhdmBase() const { + return hhdm_base; +} + +// ── Firmware subsystem accessors ───────────────────────────────────────── + +AcpiTables* Kernel::GetAcpiTables() const { + return acpi; +} + +DeviceTree* Kernel::GetDeviceTree() const { + return dt; +} + +// ── Accessors ───────────────────────────────────────────────────────────── +KernelState Kernel::GetState() const { + return state; +} + +const VersionInfo& Kernel::GetVersion() const{ + return version; +} + +const char* Kernel::GetArchName() const{ + return arch::name(); +} + +// ── Boot params & log level accessors ───────────────────────────────────── + +const BootParams& Kernel::GetBootParams() const { + return boot_params; +} + +LogLevel Kernel::GetLogLevel() const { + return log_level; +} + +void Kernel::SetLogLevel(LogLevel level) { + log_level = level; +} + +// ── State transitions ───────────────────────────────────────────────────── + +void Kernel::SetRunning() { + if (state == KernelState::Booting) + state = KernelState::Running; +} + +void Kernel::SetHalt() { + if (state != KernelState::Panicked) + state = KernelState::Halted; +} + +// ── Panic ───────────────────────────────────────────────────────────────── +// ATM it's useless +const PanicInfo& Kernel::GetPanicInfo() const { + return panic_info; +} + +[[noreturn]] void Kernel::Panic(const char* msg, const char* file, const char* func, uint32_t line) { + state = KernelState::Panicked; + + panic_info.message = msg; + panic_info.file = file; + panic_info.line = line; + panic_info.func = func; + panic_info.cpu_id = 0; // TODO: get actual CPU id when SMP is added + + // Print panic banner — kcon may or may not be initialized yet + kcon::putchar('\n'); + kcon::println("!!! KERNEL PANIC !!!"); + kcon::kprintf(" %s\n", msg); + kcon::kprintf(" at %s:%s:%u\n", file, func, line); + kcon::putchar('\n'); + + arch::halt(); +} + |
