summaryrefslogtreecommitdiff
path: root/kernel/include/kernel/kernel.h
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/include/kernel/kernel.h')
-rw-r--r--kernel/include/kernel/kernel.h206
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)