diff options
Diffstat (limited to 'kernel/include/kernel/kernel.h')
| -rw-r--r-- | kernel/include/kernel/kernel.h | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/kernel/include/kernel/kernel.h b/kernel/include/kernel/kernel.h new file mode 100644 index 0000000..5263eb9 --- /dev/null +++ b/kernel/include/kernel/kernel.h @@ -0,0 +1,206 @@ +#pragma once +// ============================================================================ +// kernel/kernel.h - Central kernel state object +// +// The Kernel class owns the canonical copy of boot-time data and serves as +// the anchor point for subsystem pointers as the OS grows. +// Exactly one instance exists (static in .bss, accessed via kernel()). +// +// Lifecycle: +// 1. .bss zero-initializes the instance (state == Uninitialized). +// 2. kernel_main() calls kernel().init(boot_info) early. +// 3. Subsystems register themselves as they come online. +// ============================================================================ + +#include <stdint.h> +#include <stddef.h> +#include <boot/boot_info.h> +#include <kernel/types.h> +#include <kernel/arch.h> +#include <kernel/firmware/acpi.h> +#include <kernel/firmware/dt.h> + +namespace kernel{ +// ── Kernel state machine ────────────────────────────────────────────────── +enum class KernelState : uint8_t { + Uninitialized = 0, // .bss zero-init lands here + Booting, // init() entered, copying boot data + Running, // All early subsystems initialized + Halted, // Clean halt requested + Panicked, // Unrecoverable error +}; + +// ── Log level ───────────────────────────────────────────────────────────── +enum class LogLevel : uint8_t { + Error = 0, + Warn, + Info, + Debug, + Trace, +}; + +// ── Version info ────────────────────────────────────────────────────────── +// Maybe it's useless +struct VersionInfo { + uint16_t major; + uint16_t minor; + uint16_t patch; + const char* codename; // Points to string literal + char string[32]; // Pre-formatted: "0.0.1-Husky" +}; + +// ── Boot parameters ────────────────────────────────────────────────────── +// Parsed from bootloader command line. Queried by many subsystems. +// TODO: +// 1) write map in lib +// 2) parse cmdline to normal map +#pragma message("FIX THIS SHIT!") +struct BootParams { + bool verbose = false; // Enable debug-level logging + bool nosmp = false; // Disable SMP even if hardware supports it + bool noacpi = false; // Skip ACPI table parsing + uint64_t mem_limit = 0; // Limit usable RAM (bytes), 0 = no limit + char cmdline[256] = {}; // Raw command line for drivers to parse +}; + +// ── Panic info ──────────────────────────────────────────────────────────── +// Filled by Kernel::Panic(), readable afterwards for crash reporting. +// TODO: add backtrace +struct PanicInfo { + const char* message = nullptr; + const char* file = nullptr; + const char* func = nullptr; + uint32_t line = 0; + uint32_t cpu_id = 0; // Which CPU panicked (SMP, Phase 7+) +}; + +// ── Kernel class ────────────────────────────────────────────────────────── +class Kernel { +public: + + // ── Accessors ───────────────────────────────────────────────────────────── + KernelState GetState() const; + const VersionInfo& GetVersion() const; + const char* GetArchName() const; + const BootParams& GetBootParams() const; + LogLevel GetLogLevel() const; + + // Boot data (copied from BootInfo — safe after boot memory reclaim) + const FramebufferInfo& GetFramebuffer() const; //TODO: don't forget to remove + PhysAddr GetKernelPhysBase() const; + VirtAddr GetKernelVirtBase() const; + uint64_t GetKernelSize() const; + VirtAddr GetHhdmBase() const; + + // ── Firmware subsystems ────────────────────────────────────────────────── + // nullptr on architectures where the subsystem doesn't exist. + // now each of them are singleton objects +#pragma message("after get heap, allocate acpi or dt in heap, and in kernel have pointers on them") +private: + AcpiTables tmp_acpitable[1]; + DeviceTree tmp_devicetree[1]; +public: + AcpiTables* GetAcpiTables() const; + DeviceTree* GetDeviceTree() const; + + // ── State transitions ───────────────────────────────────────────────────── + void SetRunning(); + void SetHalt(); + + // ── Panic ───────────────────────────────────────────────────────────────── + // The canonical way to crash the kernel. Prints panic banner and halts. + // Uses __builtin_FILE/LINE so callers don't need to pass them explicitly. + // https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html +#pragma message("rewrite panic logic, i want to have base panic class and different types of panic (null, memory and other)") + [[noreturn]] void Panic(const char* msg, + const char* file = __builtin_FILE(), + const char* func = __builtin_FUNCTION(), + uint32_t line = __builtin_LINE()); + // maybe useless + const PanicInfo& GetPanicInfo() const; + + // ── Log level ───────────────────────────────────────────────────────────── + void SetLogLevel(LogLevel level); + + // Non-copyable, non-movable + Kernel(const Kernel&) = delete; + Kernel& operator=(const Kernel&) = delete; + Kernel(Kernel&&) = delete; + Kernel& operator=(Kernel&&) = delete; + + // Trivial default constructor — .bss zero-init is sufficient. + Kernel() = default; + + // ── Init via boot_info ──────────────────────────────────────────── + void init(const BootInfo&); +private: + + // ── State ───────────────────────────────────────────────────────── + KernelState state = KernelState::Uninitialized; + + // ── Version ─────────────────────────────────────────────────────── + VersionInfo version {}; + + // ── Boot parameters ─────────────────────────────────────────────── + BootParams boot_params {}; + + // ── Panic ───────────────────────────────────────────────────────── + // maybe it useless and we can store all data inside panic function + PanicInfo panic_info {}; + + // ── Log level ───────────────────────────────────────────────────── + // Via this value different print services will do their job + LogLevel log_level = LogLevel::Info; + + // ── Boot data (owned copies) ────────────────────────────────────── + FramebufferInfo framebuffer {}; // TODO: remove + + //TODO: move it to VMM object + PhysAddr kernel_phys_base = 0; + VirtAddr kernel_virt_base = 0; + uint64_t kernel_size = 0; + VirtAddr hhdm_base = 0; + + // ── Firmware subsystems ────────────────────────────────────────── + AcpiTables* acpi = nullptr; // nullptr on aarch64 + DeviceTree* dt = nullptr; // nullptr on x86_64 +}; + +// ── Singleton accessor ──────────────────────────────────────────────────── +/* 1) We have limited stack size for our kernel (KERNEL_STACK_SIZE), + so putting kernel object to stack is bad idea + 2) .bss is always zero-filled by ELF loader, so we don't need to zeroed all objects + 3) The most important: a stack objects is only acessible local, but .bss singleton is accessible everywhere + Because of it, we need to use init function + TODO: i will have problems with SMP here + For example, serenity has one instance per CPU core and one global pointer that tracks the active one +*/ +/* + A bit info about how different kernels store Processor state: + ┌────────────┬───────────────────────────────────────────────────┬──────────────────────────┬───────────────────────────────────────────┐ + │ │ SerenityOS │ Managarm │ Linux │ + ├────────────┼───────────────────────────────────────────────────┼──────────────────────────┼───────────────────────────────────────────┤ + │ Single CPU │ Static global, simple pointer │ Static, getCpuData() │ init_task in .bss │ + ├────────────┼───────────────────────────────────────────────────┼──────────────────────────┼───────────────────────────────────────────┤ + │ SMP │ Static array + GS segment register per CPU │ Per-CPU array + accessor │ .data..percpu linker section + GS segment │ + ├────────────┼───────────────────────────────────────────────────┼──────────────────────────┼───────────────────────────────────────────┤ + │ Access │ Processor::current() reads GS MSR -> zero overhead│ getCpuData() call │ this_cpu_read() macro via GS │ + └────────────┴───────────────────────────────────────────────────┴──────────────────────────┴───────────────────────────────────────────┘ + + Technically Linux have more hard way in x86 (it stores data in cache), but in few words, yes, GS segment. + +*/ +/* + BUT: + kernel class designed to be only one in system! + Therefore singleton here is great solution, i think + And load it to .bss in RAM is kinda good too, because how often i need to get kernel comparing with task +*/ +#pragma message("In Phase7, when i will add SMP, refactor this") +Kernel& GetKernel(); +} //!namespace kernel + +// ── Convenience macros ──────────────────────────────────────────────────── +#define KERNEL_PANIC(msg) kernel().Panic(msg) +#define KERNEL_ASSERT(cond) \ + do { if (!(cond)) kernel().Panic("Assertion failed: " #cond); } while(0) |
