Skip to main content

strat9_kernel/boot/
limine.rs

1//! Limine Boot Protocol entry point
2//!
3//! This module handles the kernel entry from the Limine bootloader.
4//! Limine loads us directly in 64-bit long mode with paging enabled.
5
6use limine::{modules::InternalModule, request::*, BaseRevision};
7
8use crate::serial_println;
9
10/// Sets the base revision to the latest revision supported by the crate.
11#[used]
12#[link_section = ".requests"]
13static BASE_REVISION: BaseRevision = BaseRevision::new();
14
15/// Request the memory map
16#[used]
17#[link_section = ".requests"]
18static MEMORY_MAP: MemoryMapRequest = MemoryMapRequest::new();
19
20/// Request the framebuffer (VGA/graphics)
21#[used]
22#[link_section = ".requests"]
23static FRAMEBUFFER: FramebufferRequest = FramebufferRequest::new();
24
25/// Request the kernel address
26#[used]
27#[link_section = ".requests"]
28static EXECUTABLE_ADDRESS: ExecutableAddressRequest = ExecutableAddressRequest::new();
29
30/// Request the kernel command line
31#[used]
32#[link_section = ".requests"]
33static EXEC_CMDLINE: ExecutableCmdlineRequest = ExecutableCmdlineRequest::new();
34
35/// Request the kernel file
36#[used]
37#[link_section = ".requests"]
38static EXECUTABLE_FILE: ExecutableFileRequest = ExecutableFileRequest::new();
39
40/// Request RSDP (ACPI)
41#[used]
42#[link_section = ".requests"]
43static RSDP: RsdpRequest = RsdpRequest::new();
44
45/// Request the HHDM (Higher Half Direct Map)
46#[used]
47#[link_section = ".requests"]
48static HHDM: HhdmRequest = HhdmRequest::new();
49
50/// Request the stack size
51#[used]
52#[link_section = ".requests"]
53static STACK_SIZE: StackSizeRequest = StackSizeRequest::new().with_size(0x80000); // 512KB - increased due to AHCI/PCI scanner stack usage
54
55/// Internal module: request Limine to load /initfs/test_pid (first userspace PID test binary)
56static TEST_PID_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/test_pid");
57
58/// Internal module: request Limine to load /initfs/test_syscalls (verbose syscall test binary)
59static TEST_SYSCALLS_MODULE: InternalModule =
60    InternalModule::new().with_path(c"/initfs/test_syscalls");
61
62/// Internal module: request Limine to load /initfs/test_mem (userspace memory test binary)
63static TEST_MEM_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/test_mem");
64
65/// Internal module: request Limine to load /initfs/test_mem_stressed (userspace stressed memory test)
66static TEST_MEM_STRESSED_MODULE: InternalModule =
67    InternalModule::new().with_path(c"/initfs/test_mem_stressed");
68
69/// Internal module: request Limine to load /initfs/test_mem_region (userspace public MemoryRegion test)
70static TEST_MEM_REGION_MODULE: InternalModule =
71    InternalModule::new().with_path(c"/initfs/test_mem_region");
72
73/// Internal module: request Limine to load /initfs/test_mem_region_proc (userspace multi-process MemoryRegion test)
74static TEST_MEM_REGION_PROC_MODULE: InternalModule =
75    InternalModule::new().with_path(c"/initfs/test_mem_region_proc");
76
77/// Internal module: request Limine to load /initfs/test_exec (userspace exec regression test)
78static TEST_EXEC_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/test_exec");
79
80/// Internal module: request Limine to load /initfs/test_exec_helper (userspace exec post-exec verifier)
81static TEST_EXEC_HELPER_MODULE: InternalModule =
82    InternalModule::new().with_path(c"/initfs/test_exec_helper");
83
84/// Internal module: request Limine to load /initfs/fs-ext4 (userspace EXT4 server)
85static EXT4_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/fs-ext4");
86
87/// Internal module: request Limine to load /initfs/strate-fs-ramfs (userspace RAMFS server)
88static RAM_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/strate-fs-ramfs");
89
90/// Internal module: request Limine to load /initfs/init (init process)
91static INIT_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/init");
92
93/// Internal module: request Limine to load /initfs/console-admin (admin silo strate)
94static CONSOLE_ADMIN_MODULE: InternalModule =
95    InternalModule::new().with_path(c"/initfs/console-admin");
96/// Internal module: request Limine to load /initfs/strate-net (network silo)
97static STRATE_NET_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/strate-net");
98
99/// Internal module: request Limine to load /initfs/strate-bus (bus silo)
100static STRATE_BUS_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/strate-bus");
101
102/// Internal module: request Limine to load /initfs/bin/dhcp-client (DHCP monitor)
103static DHCP_CLIENT_MODULE: InternalModule =
104    InternalModule::new().with_path(c"/initfs/bin/dhcp-client");
105
106/// Internal module: request Limine to load /initfs/bin/ping (ICMP utility)
107static PING_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/bin/ping");
108
109/// Internal module: request Limine to load /initfs/bin/telnetd (Telnet server utility)
110static TELNETD_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/bin/telnetd");
111
112/// Internal module: request Limine to load /initfs/bin/udp-tool (UDP scheme utility)
113static UDP_TOOL_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/bin/udp-tool");
114
115/// Internal module: request Limine to load /initfs/bin/web-admin (web admin utility)
116static WEB_ADMIN_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/bin/web-admin");
117
118/// Internal module: request Limine to load /initfs/strate-wasm (WASM runtime)
119static STRATE_WASM_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/strate-wasm");
120
121/// Internal module: request Limine to load /initfs/strate-webrtc (WebRTC-native graphics runtime)
122static STRATE_WEBRTC_MODULE: InternalModule =
123    InternalModule::new().with_path(c"/initfs/strate-webrtc");
124
125/// Internal module: request Limine to load /initfs/bin/hello.wasm (WASM hello test)
126static HELLO_WASM_MODULE: InternalModule =
127    InternalModule::new().with_path(c"/initfs/bin/hello.wasm");
128
129/// Internal module: request Limine to load /initfs/wasm-test.toml (WASM test config)
130static WASM_TEST_TOML_MODULE: InternalModule =
131    InternalModule::new().with_path(c"/initfs/wasm-test.toml");
132
133/// Request modules (files loaded alongside the kernel)
134#[used]
135#[link_section = ".requests"]
136static MODULES: ModuleRequest = ModuleRequest::new().with_internal_modules(&[
137    &TEST_PID_MODULE,
138    &TEST_SYSCALLS_MODULE,
139    &TEST_MEM_MODULE,
140    &TEST_MEM_STRESSED_MODULE,
141    &TEST_MEM_REGION_MODULE,
142    &TEST_MEM_REGION_PROC_MODULE,
143    &TEST_EXEC_MODULE,
144    &TEST_EXEC_HELPER_MODULE,
145    &EXT4_MODULE,
146    &RAM_MODULE,
147    &INIT_MODULE,
148    &CONSOLE_ADMIN_MODULE,
149    &STRATE_NET_MODULE,
150    &STRATE_BUS_MODULE,
151    &DHCP_CLIENT_MODULE,
152    &PING_MODULE,
153    &TELNETD_MODULE,
154    &UDP_TOOL_MODULE,
155    &WEB_ADMIN_MODULE,
156    &STRATE_WASM_MODULE,
157    &STRATE_WEBRTC_MODULE,
158    &HELLO_WASM_MODULE,
159    &WASM_TEST_TOML_MODULE,
160]);
161
162/// Optional fs-ext4 module info (set during Limine entry).
163static mut FS_EXT4_MODULE: Option<(u64, u64)> = None;
164/// Optional test_mem module info (set during Limine entry).
165static mut TEST_MEM_ELF_MODULE: Option<(u64, u64)> = None;
166/// Optional test_syscalls module info (set during Limine entry).
167static mut TEST_SYSCALLS_ELF_MODULE: Option<(u64, u64)> = None;
168/// Optional test_mem_stressed module info (set during Limine entry).
169static mut TEST_MEM_STRESSED_ELF_MODULE: Option<(u64, u64)> = None;
170/// Optional test_mem_region module info (set during Limine entry).
171static mut TEST_MEM_REGION_ELF_MODULE: Option<(u64, u64)> = None;
172/// Optional test_mem_region_proc module info (set during Limine entry).
173static mut TEST_MEM_REGION_PROC_ELF_MODULE: Option<(u64, u64)> = None;
174/// Optional test_exec module info (set during Limine entry).
175static mut TEST_EXEC_ELF_MODULE: Option<(u64, u64)> = None;
176/// Optional test_exec_helper module info (set during Limine entry).
177static mut TEST_EXEC_HELPER_ELF_MODULE: Option<(u64, u64)> = None;
178/// Optional strate-fs-ramfs module info (set during Limine entry).
179static mut STRATE_FS_RAMFS_MODULE: Option<(u64, u64)> = None;
180/// Optional init module info (set during Limine entry).
181static mut INIT_ELF_MODULE: Option<(u64, u64)> = None;
182/// Optional console-admin module info (set during Limine entry).
183static mut CONSOLE_ADMIN_ELF_MODULE: Option<(u64, u64)> = None;
184/// Optional strate-net module info (set during Limine entry).
185static mut STRATE_NET_ELF_MODULE: Option<(u64, u64)> = None;
186/// Optional strate-bus module info (set during Limine entry).
187static mut STRATE_BUS_ELF_MODULE: Option<(u64, u64)> = None;
188/// Optional dhcp-client module info (set during Limine entry).
189static mut DHCP_CLIENT_ELF_MODULE: Option<(u64, u64)> = None;
190/// Optional ping module info (set during Limine entry).
191static mut PING_ELF_MODULE: Option<(u64, u64)> = None;
192/// Optional telnetd module info (set during Limine entry).
193static mut TELNETD_ELF_MODULE: Option<(u64, u64)> = None;
194
195/// Optional udp-tool module info (set during Limine entry).
196static mut UDP_TOOL_ELF_MODULE: Option<(u64, u64)> = None;
197/// Optional web-admin module info (set during Limine entry).
198static mut WEB_ADMIN_ELF_MODULE: Option<(u64, u64)> = None;
199/// Optional strate-wasm module info (set during Limine entry).
200static mut STRATE_WASM_ELF_MODULE: Option<(u64, u64)> = None;
201/// Optional strate-webrtc module info (set during Limine entry).
202static mut STRATE_WEBRTC_ELF_MODULE: Option<(u64, u64)> = None;
203/// Optional hello.wasm module info (set during Limine entry).
204static mut HELLO_WASM_FILE_MODULE: Option<(u64, u64)> = None;
205/// Optional wasm-test.toml module info (set during Limine entry).
206static mut WASM_TEST_TOML_FILE_MODULE: Option<(u64, u64)> = None;
207
208const MAX_BOOT_MEMORY_REGIONS: usize = 256;
209static mut BOOT_MEMORY_MAP: [super::entry::MemoryRegion; MAX_BOOT_MEMORY_REGIONS] =
210    [super::entry::MemoryRegion {
211        base: 0,
212        size: 0,
213        kind: super::entry::MemoryKind::Reserved,
214    }; MAX_BOOT_MEMORY_REGIONS];
215static mut BOOT_MEMORY_MAP_LEN: usize = 0;
216
217/// Return the fs-ext4 module (addr, size) if present.
218pub fn fs_ext4_module() -> Option<(u64, u64)> {
219    // SAFETY: Written once during early boot, then read-only.
220    unsafe { FS_EXT4_MODULE }
221}
222
223/// Return the test_mem module (addr, size) if present.
224pub fn test_mem_module() -> Option<(u64, u64)> {
225    // SAFETY: Written once during early boot, then read-only.
226    unsafe { TEST_MEM_ELF_MODULE }
227}
228
229/// Return the test_syscalls module (addr, size) if present.
230pub fn test_syscalls_module() -> Option<(u64, u64)> {
231    // SAFETY: Written once during early boot, then read-only.
232    unsafe { TEST_SYSCALLS_ELF_MODULE }
233}
234
235/// Return the test_mem_stressed module (addr, size) if present.
236pub fn test_mem_stressed_module() -> Option<(u64, u64)> {
237    // SAFETY: Written once during early boot, then read-only.
238    unsafe { TEST_MEM_STRESSED_ELF_MODULE }
239}
240
241/// Return the test_mem_region module (addr, size) if present.
242pub fn test_mem_region_module() -> Option<(u64, u64)> {
243    // SAFETY: Written once during early boot, then read-only.
244    unsafe { TEST_MEM_REGION_ELF_MODULE }
245}
246
247/// Return the test_mem_region_proc module (addr, size) if present.
248pub fn test_mem_region_proc_module() -> Option<(u64, u64)> {
249    // SAFETY: Written once during early boot, then read-only.
250    unsafe { TEST_MEM_REGION_PROC_ELF_MODULE }
251}
252
253/// Return the test_exec module (addr, size) if present.
254pub fn test_exec_module() -> Option<(u64, u64)> {
255    // SAFETY: Written once during early boot, then read-only.
256    unsafe { TEST_EXEC_ELF_MODULE }
257}
258
259/// Return the test_exec_helper module (addr, size) if present.
260pub fn test_exec_helper_module() -> Option<(u64, u64)> {
261    // SAFETY: Written once during early boot, then read-only.
262    unsafe { TEST_EXEC_HELPER_ELF_MODULE }
263}
264
265/// Return the strate-fs-ramfs module (addr, size) if present.
266pub fn strate_fs_ramfs_module() -> Option<(u64, u64)> {
267    // SAFETY: Written once during early boot, then read-only.
268    unsafe { STRATE_FS_RAMFS_MODULE }
269}
270
271/// Return the init module (addr, size) if present.
272pub fn init_module() -> Option<(u64, u64)> {
273    // SAFETY: Written once during early boot, then read-only.
274    unsafe { INIT_ELF_MODULE }
275}
276
277/// Return the console-admin module (addr, size) if present.
278pub fn console_admin_module() -> Option<(u64, u64)> {
279    // SAFETY: Written once during early boot, then read-only.
280    unsafe { CONSOLE_ADMIN_ELF_MODULE }
281}
282
283/// Return the strate-net module (addr, size) if present.
284pub fn strate_net_module() -> Option<(u64, u64)> {
285    // SAFETY: Written once during early boot, then read-only.
286    unsafe { STRATE_NET_ELF_MODULE }
287}
288
289/// Return the strate-bus module (addr, size) if present.
290pub fn strate_bus_module() -> Option<(u64, u64)> {
291    // SAFETY: Written once during early boot, then read-only.
292    unsafe { STRATE_BUS_ELF_MODULE }
293}
294
295/// Return the dhcp-client module (addr, size) if present.
296pub fn dhcp_client_module() -> Option<(u64, u64)> {
297    // SAFETY: Written once during early boot, then read-only.
298    unsafe { DHCP_CLIENT_ELF_MODULE }
299}
300
301/// Return the ping module (addr, size) if present.
302pub fn ping_module() -> Option<(u64, u64)> {
303    // SAFETY: Written once during early boot, then read-only.
304    unsafe { PING_ELF_MODULE }
305}
306
307/// Return the telnetd module (addr, size) if present.
308pub fn telnetd_module() -> Option<(u64, u64)> {
309    // SAFETY: Written once during early boot, then read-only.
310    unsafe { TELNETD_ELF_MODULE }
311}
312
313/// Return the udp-tool module (addr, size) if present.
314pub fn udp_tool_module() -> Option<(u64, u64)> {
315    // SAFETY: Written once during early boot, then read-only.
316    unsafe { UDP_TOOL_ELF_MODULE }
317}
318
319/// Return the web-admin module (addr, size) if present.
320pub fn web_admin_module() -> Option<(u64, u64)> {
321    // SAFETY: Written once during early boot, then read-only.
322    unsafe { WEB_ADMIN_ELF_MODULE }
323}
324
325/// Return the strate-wasm module (addr, size) if present.
326pub fn strate_wasm_module() -> Option<(u64, u64)> {
327    // SAFETY: Written once during early boot, then read-only.
328    unsafe { STRATE_WASM_ELF_MODULE }
329}
330
331/// Return the strate-webrtc module (addr, size) if present.
332pub fn strate_webrtc_module() -> Option<(u64, u64)> {
333    // SAFETY: Written once during early boot, then read-only.
334    unsafe { STRATE_WEBRTC_ELF_MODULE }
335}
336
337/// Return the hello.wasm module (addr, size) if present.
338pub fn hello_wasm_module() -> Option<(u64, u64)> {
339    // SAFETY: Written once during early boot, then read-only.
340    unsafe { HELLO_WASM_FILE_MODULE }
341}
342
343/// Return the wasm-test.toml module (addr, size) if present.
344pub fn wasm_test_toml_module() -> Option<(u64, u64)> {
345    // SAFETY: Written once during early boot, then read-only.
346    unsafe { WASM_TEST_TOML_FILE_MODULE }
347}
348
349/// Performs the path matches operation.
350fn path_matches(module_path: &[u8], expected_path: &[u8]) -> bool {
351    let expected_no_leading = expected_path.strip_prefix(b"/").unwrap_or(expected_path);
352    module_path == expected_path
353        || module_path.ends_with(expected_path)
354        || module_path == expected_no_leading
355        || module_path.ends_with(expected_no_leading)
356}
357
358/// Performs the module addr to phys operation.
359#[inline]
360const fn module_addr_to_phys(addr: u64, hhdm_offset: u64) -> u64 {
361    if hhdm_offset != 0 && addr >= hhdm_offset {
362        addr - hhdm_offset
363    } else {
364        addr
365    }
366}
367
368#[derive(Default, Clone, Copy)]
369struct ResolvedModules {
370    test_pid: Option<(u64, u64)>,
371    test_syscalls: Option<(u64, u64)>,
372    test_mem: Option<(u64, u64)>,
373    test_mem_stressed: Option<(u64, u64)>,
374    test_mem_region: Option<(u64, u64)>,
375    test_mem_region_proc: Option<(u64, u64)>,
376    test_exec: Option<(u64, u64)>,
377    test_exec_helper: Option<(u64, u64)>,
378    fs_ext4: Option<(u64, u64)>,
379    fs_ram: Option<(u64, u64)>,
380    init: Option<(u64, u64)>,
381    console_admin: Option<(u64, u64)>,
382    strate_net: Option<(u64, u64)>,
383    strate_bus: Option<(u64, u64)>,
384    dhcp_client: Option<(u64, u64)>,
385    ping: Option<(u64, u64)>,
386    telnetd: Option<(u64, u64)>,
387
388    udp_tool: Option<(u64, u64)>,
389    web_admin: Option<(u64, u64)>,
390    strate_wasm: Option<(u64, u64)>,
391    strate_webrtc: Option<(u64, u64)>,
392    hello_wasm: Option<(u64, u64)>,
393    wasm_test_toml: Option<(u64, u64)>,
394}
395
396/// Performs the resolve modules once operation.
397fn resolve_modules_once(modules: &[&limine::file::File], hhdm_offset: u64) -> ResolvedModules {
398    let mut resolved = ResolvedModules::default();
399    for module in modules {
400        let path = module.path().to_bytes();
401        let info = (
402            module_addr_to_phys(module.addr() as u64, hhdm_offset),
403            module.size(),
404        );
405        if path_matches(path, b"/initfs/test_pid") {
406            resolved.test_pid = Some(info);
407        } else if path_matches(path, b"/initfs/test_syscalls") {
408            resolved.test_syscalls = Some(info);
409        } else if path_matches(path, b"/initfs/test_mem") {
410            resolved.test_mem = Some(info);
411        } else if path_matches(path, b"/initfs/test_mem_stressed") {
412            resolved.test_mem_stressed = Some(info);
413        } else if path_matches(path, b"/initfs/test_mem_region") {
414            resolved.test_mem_region = Some(info);
415        } else if path_matches(path, b"/initfs/test_mem_region_proc") {
416            resolved.test_mem_region_proc = Some(info);
417        } else if path_matches(path, b"/initfs/test_exec") {
418            resolved.test_exec = Some(info);
419        } else if path_matches(path, b"/initfs/test_exec_helper") {
420            resolved.test_exec_helper = Some(info);
421        } else if path_matches(path, b"/initfs/fs-ext4") {
422            resolved.fs_ext4 = Some(info);
423        } else if path_matches(path, b"/initfs/strate-fs-ramfs") {
424            resolved.fs_ram = Some(info);
425        } else if path_matches(path, b"/initfs/init") {
426            resolved.init = Some(info);
427        } else if path_matches(path, b"/initfs/console-admin") {
428            resolved.console_admin = Some(info);
429        } else if path_matches(path, b"/initfs/strate-net") {
430            resolved.strate_net = Some(info);
431        } else if path_matches(path, b"/initfs/strate-bus") {
432            resolved.strate_bus = Some(info);
433        } else if path_matches(path, b"/initfs/bin/dhcp-client") {
434            resolved.dhcp_client = Some(info);
435        } else if path_matches(path, b"/initfs/bin/ping") {
436            resolved.ping = Some(info);
437        } else if path_matches(path, b"/initfs/bin/telnetd") {
438            resolved.telnetd = Some(info);
439        } else if path_matches(path, b"/initfs/bin/udp-tool") {
440            resolved.udp_tool = Some(info);
441        } else if path_matches(path, b"/initfs/bin/web-admin") {
442            resolved.web_admin = Some(info);
443        } else if path_matches(path, b"/initfs/strate-wasm") {
444            resolved.strate_wasm = Some(info);
445        } else if path_matches(path, b"/initfs/strate-webrtc") {
446            resolved.strate_webrtc = Some(info);
447        } else if path_matches(path, b"/initfs/bin/hello.wasm") {
448            resolved.hello_wasm = Some(info);
449        } else if path_matches(path, b"/initfs/wasm-test.toml") {
450            resolved.wasm_test_toml = Some(info);
451        }
452    }
453    resolved
454}
455
456/// Maps limine region kind.
457fn map_limine_region_kind(kind: limine::memory_map::EntryType) -> super::entry::MemoryKind {
458    if kind == limine::memory_map::EntryType::USABLE {
459        super::entry::MemoryKind::Free
460    } else if kind == limine::memory_map::EntryType::ACPI_RECLAIMABLE {
461        super::entry::MemoryKind::Reclaim
462    } else {
463        super::entry::MemoryKind::Reserved
464    }
465}
466
467/// Define the start and end markers for Limine requests
468#[used]
469#[link_section = ".requests_start_marker"]
470static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new();
471
472#[used]
473#[link_section = ".requests_end_marker"]
474static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new();
475
476/// Halt the CPU
477#[inline(always)]
478fn hlt_loop() -> ! {
479    loop {
480        unsafe {
481            core::arch::asm!("hlt", options(nomem, nostack, preserves_flags));
482        }
483    }
484}
485
486/// Kernel entry point called by Limine
487///
488/// Limine guarantees:
489/// - We're in 64-bit long mode
490/// - Paging is enabled with identity mapping + higher half
491/// - Interrupts are disabled
492/// - Stack is set up
493/// - All Limine requests have been answered
494#[no_mangle]
495#[allow(static_mut_refs)]
496pub unsafe extern "C" fn kmain() -> ! {
497    // Verify the Limine base revision is supported
498    assert!(BASE_REVISION.is_supported());
499
500    // === VERY EARLY SERIAL OUTPUT: confirms kernel entry before any init ===
501    {
502        // SAFETY: Direct UART write at earliest possible point. Raw port I/O before any setup.
503        let mut early_port = unsafe { uart_16550::SerialPort::new(0x3F8) };
504        early_port.init();
505        let _ = core::fmt::Write::write_str(
506            &mut early_port,
507            "[kmain] *** Strat9-OS kernel entry ***\r\n",
508        );
509    }
510
511    // Get framebuffer info (graphics mode provided by Limine)
512    let (
513        fb_addr,
514        fb_width,
515        fb_height,
516        fb_stride,
517        fb_bpp,
518        fb_red_mask_size,
519        fb_red_mask_shift,
520        fb_green_mask_size,
521        fb_green_mask_shift,
522        fb_blue_mask_size,
523        fb_blue_mask_shift,
524    ) = if let Some(fb_response) = FRAMEBUFFER.get_response() {
525        if let Some(fb) = fb_response.framebuffers().next() {
526            (
527                fb.addr() as u64,
528                fb.width() as u32,
529                fb.height() as u32,
530                fb.pitch() as u32,
531                fb.bpp(),
532                fb.red_mask_size(),
533                fb.red_mask_shift(),
534                fb.green_mask_size(),
535                fb.green_mask_shift(),
536                fb.blue_mask_size(),
537                fb.blue_mask_shift(),
538            )
539        } else {
540            (0, 0, 0, 0, 0, 8, 16, 8, 8, 8, 0)
541        }
542    } else {
543        (0, 0, 0, 0, 0, 8, 16, 8, 8, 8, 0)
544    };
545
546    // Get RSDP for ACPI
547    let rsdp_addr = RSDP.get_response().map(|r| r.address() as u64).unwrap_or(0);
548
549    // Initialize framebuffer abstraction with Limine-provided buffer
550    if fb_addr != 0 && fb_width != 0 && fb_height != 0 {
551        let format = crate::hardware::video::framebuffer::PixelFormat {
552            red_mask: ((1 << fb_red_mask_size) - 1) << fb_red_mask_shift,
553            red_shift: fb_red_mask_shift as u8,
554            green_mask: ((1 << fb_green_mask_size) - 1) << fb_green_mask_shift,
555            green_shift: fb_green_mask_shift as u8,
556            blue_mask: ((1 << fb_blue_mask_size) - 1) << fb_blue_mask_shift,
557            blue_shift: fb_blue_mask_shift as u8,
558            bits_per_pixel: fb_bpp as u8,
559        };
560
561        if let Err(e) = crate::hardware::video::framebuffer::Framebuffer::init_limine(
562            fb_addr, fb_width, fb_height, fb_stride, format,
563        ) {
564            serial_println!("[limine] Framebuffer init failed: {}", e);
565        }
566    }
567
568    // Get HHDM offset : critical for accessing physical memory
569    let hhdm_offset = HHDM.get_response().map(|r| r.offset()).unwrap_or(0);
570
571    // Build a kernel-local memory map from Limine entries.
572    // Keep only the first MAX_BOOT_MEMORY_REGIONS entries to avoid dynamic allocation.
573    let (memory_map_base, memory_map_size) = if let Some(memory_map_response) =
574        MEMORY_MAP.get_response()
575    {
576        let entries = memory_map_response.entries();
577        let count = core::cmp::min(entries.len(), MAX_BOOT_MEMORY_REGIONS);
578        unsafe {
579            BOOT_MEMORY_MAP_LEN = count;
580            for (i, entry) in entries.iter().take(count).enumerate() {
581                BOOT_MEMORY_MAP[i] = super::entry::MemoryRegion {
582                    base: entry.base,
583                    size: entry.length,
584                    kind: map_limine_region_kind(entry.entry_type),
585                };
586            }
587            (
588                BOOT_MEMORY_MAP.as_ptr() as u64,
589                (BOOT_MEMORY_MAP_LEN * core::mem::size_of::<super::entry::MemoryRegion>()) as u64,
590            )
591        }
592    } else {
593        (0, 0)
594    };
595
596    // Resolve loaded modules by exact path, not by index/order.
597    // Limine may return modules from config and internal requests in any order.
598    let (fallback_elf_base, fallback_elf_size, ext4_base, ext4_size, ram_base, ram_size) =
599        if let Some(module_response) = MODULES.get_response() {
600            let modules = module_response.modules();
601            crate::serial_println!("[limine] modules reported: {}", modules.len());
602            for (idx, module) in modules.iter().enumerate() {
603                #[cfg(feature = "selftest")]
604                {
605                    let raw_addr = module.addr() as u64;
606                    let phys_addr = module_addr_to_phys(raw_addr, hhdm_offset);
607                    let (m0, m1, m2, m3) = if module.size() >= 4 {
608                        unsafe {
609                            let p = raw_addr as *const u8;
610                            (
611                                core::ptr::read_volatile(p),
612                                core::ptr::read_volatile(p.add(1)),
613                                core::ptr::read_volatile(p.add(2)),
614                                core::ptr::read_volatile(p.add(3)),
615                            )
616                        }
617                    } else {
618                        (0, 0, 0, 0)
619                    };
620                    crate::serial_println!(
621                        "[limine] module[{}]: path='{}' addr={:#x} phys={:#x} magic={:02x}{:02x}{:02x}{:02x} size={}",
622                        idx,
623                        module.path().to_string_lossy(),
624                        raw_addr,
625                        phys_addr,
626                        m0,
627                        m1,
628                        m2,
629                        m3,
630                        module.size()
631                    );
632                }
633                #[cfg(not(feature = "selftest"))]
634                {
635                    crate::serial_println!(
636                        "[limine] module[{}]: path='{}' size={}",
637                        idx,
638                        module.path().to_string_lossy(),
639                        module.size()
640                    );
641                }
642            }
643            let resolved = resolve_modules_once(modules, hhdm_offset);
644            let (init_base, init_size) = resolved.test_pid.unwrap_or((0, 0));
645            let (test_syscalls_base, test_syscalls_size) = resolved.test_syscalls.unwrap_or((0, 0));
646            let (test_mem_base, test_mem_size) = resolved.test_mem.unwrap_or((0, 0));
647            let (test_mem_stressed_base, test_mem_stressed_size) =
648                resolved.test_mem_stressed.unwrap_or((0, 0));
649            let (test_mem_region_base, test_mem_region_size) =
650                resolved.test_mem_region.unwrap_or((0, 0));
651            let (test_mem_region_proc_base, test_mem_region_proc_size) =
652                resolved.test_mem_region_proc.unwrap_or((0, 0));
653            let (test_exec_base, test_exec_size) = resolved.test_exec.unwrap_or((0, 0));
654            let (test_exec_helper_base, test_exec_helper_size) =
655                resolved.test_exec_helper.unwrap_or((0, 0));
656            let (ext4_base, ext4_size) = resolved.fs_ext4.unwrap_or((0, 0));
657            let (ram_base, ram_size) = resolved.fs_ram.unwrap_or((0, 0));
658
659            if test_mem_base != 0 && test_mem_size != 0 {
660                unsafe { TEST_MEM_ELF_MODULE = Some((test_mem_base, test_mem_size)) };
661                crate::serial_println!(
662                    "[limine] /initfs/test_mem found: base={:#x} size={}",
663                    test_mem_base,
664                    test_mem_size
665                );
666            }
667            if test_syscalls_base != 0 && test_syscalls_size != 0 {
668                unsafe {
669                    TEST_SYSCALLS_ELF_MODULE = Some((test_syscalls_base, test_syscalls_size))
670                };
671                crate::serial_println!(
672                    "[limine] /initfs/test_syscalls found: base={:#x} size={}",
673                    test_syscalls_base,
674                    test_syscalls_size
675                );
676            }
677            if test_mem_stressed_base != 0 && test_mem_stressed_size != 0 {
678                unsafe {
679                    TEST_MEM_STRESSED_ELF_MODULE =
680                        Some((test_mem_stressed_base, test_mem_stressed_size))
681                };
682                crate::serial_println!(
683                    "[limine] /initfs/test_mem_stressed found: base={:#x} size={}",
684                    test_mem_stressed_base,
685                    test_mem_stressed_size
686                );
687            }
688            if test_mem_region_base != 0 && test_mem_region_size != 0 {
689                unsafe {
690                    TEST_MEM_REGION_ELF_MODULE = Some((test_mem_region_base, test_mem_region_size))
691                };
692                crate::serial_println!(
693                    "[limine] /initfs/test_mem_region found: base={:#x} size={}",
694                    test_mem_region_base,
695                    test_mem_region_size
696                );
697            } else {
698                crate::serial_println!(
699                    "[limine] WARN: /initfs/test_mem_region not found in modules"
700                );
701            }
702            if test_mem_region_proc_base != 0 && test_mem_region_proc_size != 0 {
703                unsafe {
704                    TEST_MEM_REGION_PROC_ELF_MODULE =
705                        Some((test_mem_region_proc_base, test_mem_region_proc_size))
706                };
707                crate::serial_println!(
708                    "[limine] /initfs/test_mem_region_proc found: base={:#x} size={}",
709                    test_mem_region_proc_base,
710                    test_mem_region_proc_size
711                );
712            } else {
713                crate::serial_println!(
714                    "[limine] WARN: /initfs/test_mem_region_proc not found in modules"
715                );
716            }
717            if test_exec_base != 0 && test_exec_size != 0 {
718                unsafe { TEST_EXEC_ELF_MODULE = Some((test_exec_base, test_exec_size)) };
719                crate::serial_println!(
720                    "[limine] /initfs/test_exec found: base={:#x} size={}",
721                    test_exec_base,
722                    test_exec_size
723                );
724            } else {
725                crate::serial_println!("[limine] WARN: /initfs/test_exec not found in modules");
726            }
727            if test_exec_helper_base != 0 && test_exec_helper_size != 0 {
728                unsafe {
729                    TEST_EXEC_HELPER_ELF_MODULE =
730                        Some((test_exec_helper_base, test_exec_helper_size))
731                };
732                crate::serial_println!(
733                    "[limine] /initfs/test_exec_helper found: base={:#x} size={}",
734                    test_exec_helper_base,
735                    test_exec_helper_size
736                );
737            } else {
738                crate::serial_println!(
739                    "[limine] WARN: /initfs/test_exec_helper not found in modules"
740                );
741            }
742
743            // New modules: init + console-admin
744            if let Some((base, size)) = resolved.init {
745                unsafe { INIT_ELF_MODULE = Some((base, size)) };
746                crate::serial_println!(
747                    "[limine] /initfs/init found: base={:#x} size={}",
748                    base,
749                    size
750                );
751            } else {
752                crate::serial_println!("[limine] WARN: /initfs/init not found in modules");
753            }
754            if let Some((base, size)) = resolved.console_admin {
755                unsafe { CONSOLE_ADMIN_ELF_MODULE = Some((base, size)) };
756                crate::serial_println!(
757                    "[limine] /initfs/console-admin found: base={:#x} size={}",
758                    base,
759                    size
760                );
761            } else {
762                crate::serial_println!("[limine] WARN: /initfs/console-admin not found in modules");
763            }
764            if let Some((base, size)) = resolved.strate_net {
765                unsafe { STRATE_NET_ELF_MODULE = Some((base, size)) };
766                crate::serial_println!(
767                    "[limine] /initfs/strate-net found: base={:#x} size={}",
768                    base,
769                    size
770                );
771            } else {
772                crate::serial_println!("[limine] WARN: /initfs/strate-net not found in modules");
773            }
774            if let Some((base, size)) = resolved.strate_bus {
775                unsafe { STRATE_BUS_ELF_MODULE = Some((base, size)) };
776                crate::serial_println!(
777                    "[limine] /initfs/strate-bus found: base={:#x} size={}",
778                    base,
779                    size
780                );
781            } else {
782                crate::serial_println!("[limine] WARN: /initfs/strate-bus not found in modules");
783            }
784            if let Some((base, size)) = resolved.dhcp_client {
785                unsafe { DHCP_CLIENT_ELF_MODULE = Some((base, size)) };
786                crate::serial_println!(
787                    "[limine] /initfs/bin/dhcp-client found: base={:#x} size={}",
788                    base,
789                    size
790                );
791            } else {
792                crate::serial_println!(
793                    "[limine] WARN: /initfs/bin/dhcp-client not found in modules"
794                );
795            }
796            if let Some((base, size)) = resolved.ping {
797                unsafe { PING_ELF_MODULE = Some((base, size)) };
798                crate::serial_println!(
799                    "[limine] /initfs/bin/ping found: base={:#x} size={}",
800                    base,
801                    size
802                );
803            } else {
804                crate::serial_println!("[limine] WARN: /initfs/bin/ping not found in modules");
805            }
806            if let Some((base, size)) = resolved.telnetd {
807                unsafe { TELNETD_ELF_MODULE = Some((base, size)) };
808                crate::serial_println!(
809                    "[limine] /initfs/bin/telnetd found: base={:#x} size={}",
810                    base,
811                    size
812                );
813            } else {
814                crate::serial_println!("[limine] WARN: /initfs/bin/telnetd not found in modules");
815            }
816
817            if let Some((base, size)) = resolved.udp_tool {
818                unsafe { UDP_TOOL_ELF_MODULE = Some((base, size)) };
819                crate::serial_println!(
820                    "[limine] /initfs/bin/udp-tool found: base={:#x} size={}",
821                    base,
822                    size
823                );
824            } else {
825                crate::serial_println!("[limine] WARN: /initfs/bin/udp-tool not found in modules");
826            }
827            if let Some((base, size)) = resolved.web_admin {
828                unsafe { WEB_ADMIN_ELF_MODULE = Some((base, size)) };
829                crate::serial_println!(
830                    "[limine] /initfs/bin/web-admin found: base={:#x} size={}",
831                    base,
832                    size
833                );
834            } else {
835                crate::serial_println!("[limine] WARN: /initfs/bin/web-admin not found in modules");
836            }
837            if let Some((base, size)) = resolved.strate_wasm {
838                unsafe { STRATE_WASM_ELF_MODULE = Some((base, size)) };
839                crate::serial_println!(
840                    "[limine] /initfs/strate-wasm found: base={:#x} size={}",
841                    base,
842                    size
843                );
844            } else {
845                crate::serial_println!("[limine] WARN: /initfs/strate-wasm not found in modules");
846            }
847            if let Some((base, size)) = resolved.strate_webrtc {
848                unsafe { STRATE_WEBRTC_ELF_MODULE = Some((base, size)) };
849                crate::serial_println!(
850                    "[limine] /initfs/strate-webrtc found: base={:#x} size={}",
851                    base,
852                    size
853                );
854            } else {
855                crate::serial_println!("[limine] WARN: /initfs/strate-webrtc not found in modules");
856            }
857            if let Some((base, size)) = resolved.hello_wasm {
858                unsafe { HELLO_WASM_FILE_MODULE = Some((base, size)) };
859                crate::serial_println!(
860                    "[limine] /initfs/bin/hello.wasm found: base={:#x} size={}",
861                    base,
862                    size
863                );
864            } else {
865                crate::serial_println!(
866                    "[limine] WARN: /initfs/bin/hello.wasm not found in modules"
867                );
868            }
869            if let Some((base, size)) = resolved.wasm_test_toml {
870                unsafe { WASM_TEST_TOML_FILE_MODULE = Some((base, size)) };
871                crate::serial_println!(
872                    "[limine] /initfs/wasm-test.toml found: base={:#x} size={}",
873                    base,
874                    size
875                );
876            } else {
877                crate::serial_println!(
878                    "[limine] WARN: /initfs/wasm-test.toml not found in modules"
879                );
880            }
881
882            if init_base == 0 {
883                crate::serial_println!("[limine] WARN: /initfs/test_pid not found in modules");
884            }
885            if ext4_base == 0 {
886                crate::serial_println!("[limine] WARN: /initfs/fs-ext4 not found in modules");
887            }
888            if ram_base == 0 {
889                crate::serial_println!(
890                    "[limine] WARN: /initfs/strate-fs-ramfs not found in modules"
891                );
892            }
893            (
894                init_base, init_size, ext4_base, ext4_size, ram_base, ram_size,
895            )
896        } else {
897            (0u64, 0u64, 0u64, 0u64, 0u64, 0u64)
898        };
899
900    if ext4_base != 0 && ext4_size != 0 {
901        // SAFETY: set once during early boot.
902        unsafe {
903            FS_EXT4_MODULE = Some((ext4_base, ext4_size));
904        }
905    }
906
907    if ram_base != 0 && ram_size != 0 {
908        // SAFETY: set once during early boot.
909        unsafe {
910            STRATE_FS_RAMFS_MODULE = Some((ram_base, ram_size));
911        }
912    }
913
914    // Extract kernel command line from Limine
915    let (cmdline_ptr, cmdline_len) = if let Some(cmdline_resp) = EXEC_CMDLINE.get_response() {
916        let cstr = cmdline_resp.cmdline();
917        let bytes = cstr.to_bytes_with_nul();
918        let ptr = bytes.as_ptr() as u64;
919        let len = bytes.len() as u64;
920        if let Ok(s) = cstr.to_str() {
921            crate::serial_println!("[limine] cmdline: '{}'", s);
922        }
923        (ptr, len)
924    } else {
925        crate::serial_println!("[limine] no cmdline provided");
926        (0, 0)
927    };
928
929    let args = super::entry::KernelArgs {
930        magic: strat9_abi::boot::STRAT9_BOOT_MAGIC,
931        abi_version: strat9_abi::boot::STRAT9_BOOT_ABI_VERSION,
932        kernel_base: EXECUTABLE_ADDRESS
933            .get_response()
934            .map(|r| r.physical_base())
935            .unwrap_or(0x100000),
936        kernel_size: EXECUTABLE_FILE
937            .get_response()
938            .map(|r| r.file().size())
939            .unwrap_or(0),
940        stack_base: 0x80000,
941        stack_size: 0x10000,
942        env_base: 0,
943        env_size: 0,
944        acpi_rsdp_base: rsdp_addr,
945        acpi_rsdp_size: if rsdp_addr != 0 { 36 } else { 0 },
946        memory_map_base,
947        memory_map_size,
948        initfs_base: fallback_elf_base,
949        initfs_size: fallback_elf_size,
950        framebuffer_addr: fb_addr,
951        framebuffer_width: fb_width,
952        framebuffer_height: fb_height,
953        framebuffer_stride: fb_stride,
954        framebuffer_bpp: fb_bpp,
955        framebuffer_red_mask_size: fb_red_mask_size,
956        framebuffer_red_mask_shift: fb_red_mask_shift,
957        framebuffer_green_mask_size: fb_green_mask_size,
958        framebuffer_green_mask_shift: fb_green_mask_shift,
959        framebuffer_blue_mask_size: fb_blue_mask_size,
960        framebuffer_blue_mask_shift: fb_blue_mask_shift,
961        _padding1: [0; 4],
962        hhdm_offset,
963        cmdline_ptr,
964        cmdline_len,
965    };
966
967    // Call kernel main
968    crate::kernel_main(&args as *const _);
969}