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();
}
|