// ============================================================================ // core/kernel.cpp - Kernel singleton implementation // ============================================================================ #include #include 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(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=" 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(); }