summaryrefslogtreecommitdiff
path: root/kernel/core/kernel_main.cpp
blob: cf95b592574504044dc60bab64a256c56f2e67d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// ============================================================================
// core/kernel_main.cpp - Kernel entry point
//
// Called by arch-specific entry.S after stack setup.
// Receives BootInfo* by the UEFI loader (or in future from other loader).
// ============================================================================

#include <boot/boot_info.h>
#include <kernel/kprint.h>
#include <kernel/arch.h>
#include <kernel/kernel.h>
#include "Processor.h"

using namespace kernel;
// ── Memory region type names ───────────────────────────────────────────────

namespace {
//TODO: Move it to another cpp/h file
//TODO: use reflection to get field name
[[nodiscard]] constexpr const char* mem_type_name(MemoryRegionType type) {
    switch (type) {
        case MemoryRegionType::Usable:                return "Usable";
        case MemoryRegionType::Reserved:              return "Reserved";
        case MemoryRegionType::AcpiReclaimable:       return "ACPI Reclaimable";
        case MemoryRegionType::AcpiNvs:               return "ACPI NVS";
        case MemoryRegionType::BootloaderReclaimable: return "Boot Reclaimable";
        case MemoryRegionType::KernelAndModules:      return "Kernel";
        case MemoryRegionType::Framebuffer:           return "Framebuffer";
    }
    return "Unknown";
}

} // anonymous namespace

// ── Kernel entry ───────────────────────────────────────────────────────────
// Called from entry.S with BootInfo* in RDI (x86_64) / X0 (AArch64).
extern "C" void kernel_main(BootInfo* boot_info) {
    // Validate magic — if wrong we can't print, just halt.
    if (boot_info->magic != BOOT_INFO_MAGIC)
        arch::halt();

    // Initialize framebuffer console (needed before Kernel::init for logging).
    // TODO: Add driver skeleton and move framebuffer to early drivers.
    kcon::init(boot_info->framebuffer);

    // Initialize the kernel object — copies boot data, safe to use after this.
    GetKernel().init(*boot_info);

    // Store arch-specific per-CPU state (Phase 2: GDT/IDT, VBAR/GIC, etc.).
    processor().InitEarly(*boot_info);

    // ── Banner ─────────────────────────────────────────────────────────

    kcon::println("========================================");
    kcon::kprintf("  Bastion Kernel %s\n", GetKernel().GetVersion().string);
    kcon::kprintf("  Architecture: %s\n", GetKernel().GetArchName());
    kcon::println("========================================");
    kcon::putchar('\n');

    // ── Framebuffer info ───────────────────────────────────────────────

    kcon::kprintf("Framebuffer: %ux%u, pitch=%u, base=%x\n",
        GetKernel().GetFramebuffer().width,
        GetKernel().GetFramebuffer().height,
        GetKernel().GetFramebuffer().pitch,
        GetKernel().GetFramebuffer().base);
    kcon::putchar('\n');

    // ── Firmware tables ────────────────────────────────────────────────
    if (GetKernel().GetAcpiTables() && GetKernel().GetAcpiTables()->GetRsdpAddress())
        kcon::kprintf("ACPI RSDP at: %x\n", GetKernel().GetAcpiTables()->GetRsdpAddress());
    if (GetKernel().GetDeviceTree() && GetKernel().GetDeviceTree()->GetFdtAddress())
        kcon::kprintf("Device Tree at: %x\n", GetKernel().GetDeviceTree()->GetFdtAddress());
    kcon::putchar('\n');

    // ── Memory map (read directly from boot_info, consumed by PMM later) ──

    kcon::kprintf("Memory map (%u entries):\n", boot_info->memory_map_count);

    uint64_t total_usable = 0;
    for (uint64_t i = 0; i < boot_info->memory_map_count; i++) {
        const auto& region = boot_info->memory_map[i];

        // Skip tiny reserved regions to avoid flooding the console.
        if (region.type == MemoryRegionType::Reserved && region.length < 0x10000)
            continue;

        kcon::kprintf("  %x - %x  [%s]\n",
            region.base,
            region.base + region.length,
            mem_type_name(region.type));

        if (region.type == MemoryRegionType::Usable)
            total_usable += region.length;
    }

    kcon::putchar('\n');
    kcon::kprintf("Total usable memory: %u MiB\n", total_usable / (1024u * 1024u));

    // ── Kernel info ────────────────────────────────────────────────────

    kcon::putchar('\n');
    kcon::kprintf("Kernel loaded at phys %x, virt %x, size %u KiB\n",
        GetKernel().GetKernelPhysBase(),
        GetKernel().GetKernelPhysBase(),
        GetKernel().GetKernelSize() / 1024u);

    // ── Done (for now) ─────────────────────────────────────────────────

    GetKernel().SetRunning();

    kcon::putchar('\n');
    kcon::println("Hello, World from BastionOS!");
    kcon::putchar('\n');
    kcon::println("Kernel initialized successfully.");
    kcon::println("Next: GDT, IDT, paging, memory allocator...");
    kcon::println("Halting.");

    //KERNEL_PANIC("panic test");

    GetKernel().SetHalt();
    arch::halt();
}