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 file
31#[used]
32#[link_section = ".requests"]
33static EXECUTABLE_FILE: ExecutableFileRequest = ExecutableFileRequest::new();
34
35/// Request RSDP (ACPI)
36#[used]
37#[link_section = ".requests"]
38static RSDP: RsdpRequest = RsdpRequest::new();
39
40/// Request the HHDM (Higher Half Direct Map)
41#[used]
42#[link_section = ".requests"]
43static HHDM: HhdmRequest = HhdmRequest::new();
44
45/// Request the stack size
46#[used]
47#[link_section = ".requests"]
48static STACK_SIZE: StackSizeRequest = StackSizeRequest::new().with_size(0x10000); // 64KB
49
50/// Internal module: request Limine to load /initfs/test_pid (first userspace PID test binary)
51static TEST_PID_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/test_pid");
52/// Internal module: request Limine to load /initfs/test_syscalls (verbose syscall test binary)
53static TEST_SYSCALLS_MODULE: InternalModule =
54    InternalModule::new().with_path(c"/initfs/test_syscalls");
55/// Internal module: request Limine to load /initfs/test_mem (userspace memory test binary)
56static TEST_MEM_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/test_mem");
57/// Internal module: request Limine to load /initfs/test_mem_stressed (userspace stressed memory test)
58static TEST_MEM_STRESSED_MODULE: InternalModule =
59    InternalModule::new().with_path(c"/initfs/test_mem_stressed");
60/// Internal module: request Limine to load /initfs/fs-ext4 (userspace EXT4 server)
61static EXT4_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/fs-ext4");
62/// Internal module: request Limine to load /initfs/strate-fs-ramfs (userspace RAMFS server)
63static RAM_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/strate-fs-ramfs");
64/// Internal module: request Limine to load /initfs/init (init process)
65static INIT_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/init");
66/// Internal module: request Limine to load /initfs/console-admin (admin silo strate)
67static CONSOLE_ADMIN_MODULE: InternalModule =
68    InternalModule::new().with_path(c"/initfs/console-admin");
69/// Internal module: request Limine to load /initfs/strate-net (network silo)
70static STRATE_NET_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/strate-net");
71/// Internal module: request Limine to load /initfs/strate-bus (bus silo)
72static STRATE_BUS_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/strate-bus");
73/// Internal module: request Limine to load /initfs/bin/dhcp-client (DHCP monitor)
74static DHCP_CLIENT_MODULE: InternalModule =
75    InternalModule::new().with_path(c"/initfs/bin/dhcp-client");
76/// Internal module: request Limine to load /initfs/bin/ping (ICMP utility)
77static PING_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/bin/ping");
78/// Internal module: request Limine to load /initfs/bin/telnetd (Telnet server utility)
79static TELNETD_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/bin/telnetd");
80/// Internal module: request Limine to load /initfs/bin/udp-tool (UDP scheme utility)
81static UDP_TOOL_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/bin/udp-tool");
82/// Internal module: request Limine to load /initfs/strate-wasm (WASM runtime)
83static STRATE_WASM_MODULE: InternalModule = InternalModule::new().with_path(c"/initfs/strate-wasm");
84/// Internal module: request Limine to load /initfs/strate-webrtc (WebRTC-native graphics runtime)
85static STRATE_WEBRTC_MODULE: InternalModule =
86    InternalModule::new().with_path(c"/initfs/strate-webrtc");
87/// Internal module: request Limine to load /initfs/bin/hello.wasm (WASM hello test)
88static HELLO_WASM_MODULE: InternalModule =
89    InternalModule::new().with_path(c"/initfs/bin/hello.wasm");
90/// Internal module: request Limine to load /initfs/wasm-test.toml (WASM test config)
91static WASM_TEST_TOML_MODULE: InternalModule =
92    InternalModule::new().with_path(c"/initfs/wasm-test.toml");
93
94/// Request modules (files loaded alongside the kernel)
95#[used]
96#[link_section = ".requests"]
97static MODULES: ModuleRequest = ModuleRequest::new().with_internal_modules(&[
98    &TEST_PID_MODULE,
99    &TEST_SYSCALLS_MODULE,
100    &TEST_MEM_MODULE,
101    &TEST_MEM_STRESSED_MODULE,
102    &EXT4_MODULE,
103    &RAM_MODULE,
104    &INIT_MODULE,
105    &CONSOLE_ADMIN_MODULE,
106    &STRATE_NET_MODULE,
107    &STRATE_BUS_MODULE,
108    &DHCP_CLIENT_MODULE,
109    &PING_MODULE,
110    &TELNETD_MODULE,
111    &UDP_TOOL_MODULE,
112    &STRATE_WASM_MODULE,
113    &STRATE_WEBRTC_MODULE,
114    &HELLO_WASM_MODULE,
115    &WASM_TEST_TOML_MODULE,
116]);
117
118/// Optional fs-ext4 module info (set during Limine entry).
119static mut FS_EXT4_MODULE: Option<(u64, u64)> = None;
120/// Optional test_mem module info (set during Limine entry).
121static mut TEST_MEM_ELF_MODULE: Option<(u64, u64)> = None;
122/// Optional test_syscalls module info (set during Limine entry).
123static mut TEST_SYSCALLS_ELF_MODULE: Option<(u64, u64)> = None;
124/// Optional test_mem_stressed module info (set during Limine entry).
125static mut TEST_MEM_STRESSED_ELF_MODULE: Option<(u64, u64)> = None;
126/// Optional strate-fs-ramfs module info (set during Limine entry).
127static mut STRATE_FS_RAMFS_MODULE: Option<(u64, u64)> = None;
128/// Optional init module info (set during Limine entry).
129static mut INIT_ELF_MODULE: Option<(u64, u64)> = None;
130/// Optional console-admin module info (set during Limine entry).
131static mut CONSOLE_ADMIN_ELF_MODULE: Option<(u64, u64)> = None;
132/// Optional strate-net module info (set during Limine entry).
133static mut STRATE_NET_ELF_MODULE: Option<(u64, u64)> = None;
134/// Optional strate-bus module info (set during Limine entry).
135static mut STRATE_BUS_ELF_MODULE: Option<(u64, u64)> = None;
136/// Optional dhcp-client module info (set during Limine entry).
137static mut DHCP_CLIENT_ELF_MODULE: Option<(u64, u64)> = None;
138/// Optional ping module info (set during Limine entry).
139static mut PING_ELF_MODULE: Option<(u64, u64)> = None;
140/// Optional telnetd module info (set during Limine entry).
141static mut TELNETD_ELF_MODULE: Option<(u64, u64)> = None;
142/// Optional udp-tool module info (set during Limine entry).
143static mut UDP_TOOL_ELF_MODULE: Option<(u64, u64)> = None;
144/// Optional strate-wasm module info (set during Limine entry).
145static mut STRATE_WASM_ELF_MODULE: Option<(u64, u64)> = None;
146/// Optional strate-webrtc module info (set during Limine entry).
147static mut STRATE_WEBRTC_ELF_MODULE: Option<(u64, u64)> = None;
148/// Optional hello.wasm module info (set during Limine entry).
149static mut HELLO_WASM_FILE_MODULE: Option<(u64, u64)> = None;
150/// Optional wasm-test.toml module info (set during Limine entry).
151static mut WASM_TEST_TOML_FILE_MODULE: Option<(u64, u64)> = None;
152
153const MAX_BOOT_MEMORY_REGIONS: usize = 256;
154static mut BOOT_MEMORY_MAP: [super::entry::MemoryRegion; MAX_BOOT_MEMORY_REGIONS] =
155    [super::entry::MemoryRegion {
156        base: 0,
157        size: 0,
158        kind: super::entry::MemoryKind::Reserved,
159    }; MAX_BOOT_MEMORY_REGIONS];
160static mut BOOT_MEMORY_MAP_LEN: usize = 0;
161
162/// Return the fs-ext4 module (addr, size) if present.
163pub fn fs_ext4_module() -> Option<(u64, u64)> {
164    // SAFETY: Written once during early boot, then read-only.
165    unsafe { FS_EXT4_MODULE }
166}
167
168/// Return the test_mem module (addr, size) if present.
169pub fn test_mem_module() -> Option<(u64, u64)> {
170    // SAFETY: Written once during early boot, then read-only.
171    unsafe { TEST_MEM_ELF_MODULE }
172}
173
174/// Return the test_syscalls module (addr, size) if present.
175pub fn test_syscalls_module() -> Option<(u64, u64)> {
176    // SAFETY: Written once during early boot, then read-only.
177    unsafe { TEST_SYSCALLS_ELF_MODULE }
178}
179
180/// Return the test_mem_stressed module (addr, size) if present.
181pub fn test_mem_stressed_module() -> Option<(u64, u64)> {
182    // SAFETY: Written once during early boot, then read-only.
183    unsafe { TEST_MEM_STRESSED_ELF_MODULE }
184}
185
186/// Return the strate-fs-ramfs module (addr, size) if present.
187pub fn strate_fs_ramfs_module() -> Option<(u64, u64)> {
188    // SAFETY: Written once during early boot, then read-only.
189    unsafe { STRATE_FS_RAMFS_MODULE }
190}
191
192/// Return the init module (addr, size) if present.
193pub fn init_module() -> Option<(u64, u64)> {
194    // SAFETY: Written once during early boot, then read-only.
195    unsafe { INIT_ELF_MODULE }
196}
197
198/// Return the console-admin module (addr, size) if present.
199pub fn console_admin_module() -> Option<(u64, u64)> {
200    // SAFETY: Written once during early boot, then read-only.
201    unsafe { CONSOLE_ADMIN_ELF_MODULE }
202}
203
204/// Return the strate-net module (addr, size) if present.
205pub fn strate_net_module() -> Option<(u64, u64)> {
206    // SAFETY: Written once during early boot, then read-only.
207    unsafe { STRATE_NET_ELF_MODULE }
208}
209
210/// Return the strate-bus module (addr, size) if present.
211pub fn strate_bus_module() -> Option<(u64, u64)> {
212    // SAFETY: Written once during early boot, then read-only.
213    unsafe { STRATE_BUS_ELF_MODULE }
214}
215
216/// Return the dhcp-client module (addr, size) if present.
217pub fn dhcp_client_module() -> Option<(u64, u64)> {
218    // SAFETY: Written once during early boot, then read-only.
219    unsafe { DHCP_CLIENT_ELF_MODULE }
220}
221
222/// Return the ping module (addr, size) if present.
223pub fn ping_module() -> Option<(u64, u64)> {
224    // SAFETY: Written once during early boot, then read-only.
225    unsafe { PING_ELF_MODULE }
226}
227
228/// Return the telnetd module (addr, size) if present.
229pub fn telnetd_module() -> Option<(u64, u64)> {
230    // SAFETY: Written once during early boot, then read-only.
231    unsafe { TELNETD_ELF_MODULE }
232}
233
234/// Return the udp-tool module (addr, size) if present.
235pub fn udp_tool_module() -> Option<(u64, u64)> {
236    // SAFETY: Written once during early boot, then read-only.
237    unsafe { UDP_TOOL_ELF_MODULE }
238}
239
240/// Return the strate-wasm module (addr, size) if present.
241pub fn strate_wasm_module() -> Option<(u64, u64)> {
242    // SAFETY: Written once during early boot, then read-only.
243    unsafe { STRATE_WASM_ELF_MODULE }
244}
245
246/// Return the strate-webrtc module (addr, size) if present.
247pub fn strate_webrtc_module() -> Option<(u64, u64)> {
248    // SAFETY: Written once during early boot, then read-only.
249    unsafe { STRATE_WEBRTC_ELF_MODULE }
250}
251
252/// Return the hello.wasm module (addr, size) if present.
253pub fn hello_wasm_module() -> Option<(u64, u64)> {
254    // SAFETY: Written once during early boot, then read-only.
255    unsafe { HELLO_WASM_FILE_MODULE }
256}
257
258/// Return the wasm-test.toml module (addr, size) if present.
259pub fn wasm_test_toml_module() -> Option<(u64, u64)> {
260    // SAFETY: Written once during early boot, then read-only.
261    unsafe { WASM_TEST_TOML_FILE_MODULE }
262}
263
264/// Performs the path matches operation.
265fn path_matches(module_path: &[u8], expected_path: &[u8]) -> bool {
266    let expected_no_leading = expected_path.strip_prefix(b"/").unwrap_or(expected_path);
267    module_path == expected_path
268        || module_path.ends_with(expected_path)
269        || module_path == expected_no_leading
270        || module_path.ends_with(expected_no_leading)
271}
272
273/// Performs the module addr to phys operation.
274#[inline]
275const fn module_addr_to_phys(addr: u64, hhdm_offset: u64) -> u64 {
276    if hhdm_offset != 0 && addr >= hhdm_offset {
277        addr - hhdm_offset
278    } else {
279        addr
280    }
281}
282
283#[derive(Default, Clone, Copy)]
284struct ResolvedModules {
285    test_pid: Option<(u64, u64)>,
286    test_syscalls: Option<(u64, u64)>,
287    test_mem: Option<(u64, u64)>,
288    test_mem_stressed: Option<(u64, u64)>,
289    fs_ext4: Option<(u64, u64)>,
290    fs_ram: Option<(u64, u64)>,
291    init: Option<(u64, u64)>,
292    console_admin: Option<(u64, u64)>,
293    strate_net: Option<(u64, u64)>,
294    strate_bus: Option<(u64, u64)>,
295    dhcp_client: Option<(u64, u64)>,
296    ping: Option<(u64, u64)>,
297    telnetd: Option<(u64, u64)>,
298    udp_tool: Option<(u64, u64)>,
299    strate_wasm: Option<(u64, u64)>,
300    strate_webrtc: Option<(u64, u64)>,
301    hello_wasm: Option<(u64, u64)>,
302    wasm_test_toml: Option<(u64, u64)>,
303}
304
305/// Performs the resolve modules once operation.
306fn resolve_modules_once(modules: &[&limine::file::File], hhdm_offset: u64) -> ResolvedModules {
307    let mut resolved = ResolvedModules::default();
308    for module in modules {
309        let path = module.path().to_bytes();
310        let info = (
311            module_addr_to_phys(module.addr() as u64, hhdm_offset),
312            module.size(),
313        );
314        if path_matches(path, b"/initfs/test_pid") {
315            resolved.test_pid = Some(info);
316        } else if path_matches(path, b"/initfs/test_syscalls") {
317            resolved.test_syscalls = Some(info);
318        } else if path_matches(path, b"/initfs/test_mem") {
319            resolved.test_mem = Some(info);
320        } else if path_matches(path, b"/initfs/test_mem_stressed") {
321            resolved.test_mem_stressed = Some(info);
322        } else if path_matches(path, b"/initfs/fs-ext4") {
323            resolved.fs_ext4 = Some(info);
324        } else if path_matches(path, b"/initfs/strate-fs-ramfs") {
325            resolved.fs_ram = Some(info);
326        } else if path_matches(path, b"/initfs/init") {
327            resolved.init = Some(info);
328        } else if path_matches(path, b"/initfs/console-admin") {
329            resolved.console_admin = Some(info);
330        } else if path_matches(path, b"/initfs/strate-net") {
331            resolved.strate_net = Some(info);
332        } else if path_matches(path, b"/initfs/strate-bus") {
333            resolved.strate_bus = Some(info);
334        } else if path_matches(path, b"/initfs/bin/dhcp-client") {
335            resolved.dhcp_client = Some(info);
336        } else if path_matches(path, b"/initfs/bin/ping") {
337            resolved.ping = Some(info);
338        } else if path_matches(path, b"/initfs/bin/telnetd") {
339            resolved.telnetd = Some(info);
340        } else if path_matches(path, b"/initfs/bin/udp-tool") {
341            resolved.udp_tool = Some(info);
342        } else if path_matches(path, b"/initfs/strate-wasm") {
343            resolved.strate_wasm = Some(info);
344        } else if path_matches(path, b"/initfs/strate-webrtc") {
345            resolved.strate_webrtc = Some(info);
346        } else if path_matches(path, b"/initfs/bin/hello.wasm") {
347            resolved.hello_wasm = Some(info);
348        } else if path_matches(path, b"/initfs/wasm-test.toml") {
349            resolved.wasm_test_toml = Some(info);
350        }
351    }
352    resolved
353}
354
355/// Maps limine region kind.
356fn map_limine_region_kind(kind: limine::memory_map::EntryType) -> super::entry::MemoryKind {
357    if kind == limine::memory_map::EntryType::USABLE {
358        super::entry::MemoryKind::Free
359    } else if kind == limine::memory_map::EntryType::ACPI_RECLAIMABLE {
360        super::entry::MemoryKind::Reclaim
361    } else {
362        super::entry::MemoryKind::Reserved
363    }
364}
365
366/// Define the start and end markers for Limine requests
367#[used]
368#[link_section = ".requests_start_marker"]
369static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new();
370
371#[used]
372#[link_section = ".requests_end_marker"]
373static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new();
374
375/// Halt the CPU
376#[inline(always)]
377fn hlt_loop() -> ! {
378    loop {
379        unsafe {
380            core::arch::asm!("hlt", options(nomem, nostack, preserves_flags));
381        }
382    }
383}
384
385/// Kernel entry point called by Limine
386///
387/// Limine guarantees:
388/// - We're in 64-bit long mode
389/// - Paging is enabled with identity mapping + higher half
390/// - Interrupts are disabled
391/// - Stack is set up
392/// - All Limine requests have been answered
393#[no_mangle]
394#[allow(static_mut_refs)]
395pub unsafe extern "C" fn kmain() -> ! {
396    // Verify the Limine base revision is supported
397    assert!(BASE_REVISION.is_supported());
398
399    // Get framebuffer info (graphics mode provided by Limine)
400    let (
401        fb_addr,
402        fb_width,
403        fb_height,
404        fb_stride,
405        fb_bpp,
406        fb_red_mask_size,
407        fb_red_mask_shift,
408        fb_green_mask_size,
409        fb_green_mask_shift,
410        fb_blue_mask_size,
411        fb_blue_mask_shift,
412    ) = if let Some(fb_response) = FRAMEBUFFER.get_response() {
413        if let Some(fb) = fb_response.framebuffers().next() {
414            (
415                fb.addr() as u64,
416                fb.width() as u32,
417                fb.height() as u32,
418                fb.pitch() as u32,
419                fb.bpp(),
420                fb.red_mask_size(),
421                fb.red_mask_shift(),
422                fb.green_mask_size(),
423                fb.green_mask_shift(),
424                fb.blue_mask_size(),
425                fb.blue_mask_shift(),
426            )
427        } else {
428            (0, 0, 0, 0, 0, 8, 16, 8, 8, 8, 0)
429        }
430    } else {
431        (0, 0, 0, 0, 0, 8, 16, 8, 8, 8, 0)
432    };
433
434    // Get RSDP for ACPI
435    let rsdp_addr = RSDP.get_response().map(|r| r.address() as u64).unwrap_or(0);
436
437    // Initialize framebuffer abstraction with Limine-provided buffer
438    if fb_addr != 0 && fb_width != 0 && fb_height != 0 {
439        let format = crate::hardware::video::framebuffer::PixelFormat {
440            red_mask: ((1 << fb_red_mask_size) - 1) << fb_red_mask_shift,
441            red_shift: fb_red_mask_shift as u8,
442            green_mask: ((1 << fb_green_mask_size) - 1) << fb_green_mask_shift,
443            green_shift: fb_green_mask_shift as u8,
444            blue_mask: ((1 << fb_blue_mask_size) - 1) << fb_blue_mask_shift,
445            blue_shift: fb_blue_mask_shift as u8,
446            bits_per_pixel: fb_bpp as u8,
447        };
448
449        if let Err(e) = crate::hardware::video::framebuffer::Framebuffer::init_limine(
450            fb_addr, fb_width, fb_height, fb_stride, format,
451        ) {
452            serial_println!("[limine] Framebuffer init failed: {}", e);
453        }
454    }
455
456    // Get HHDM offset — critical for accessing physical memory
457    let hhdm_offset = HHDM.get_response().map(|r| r.offset()).unwrap_or(0);
458
459    // Build a kernel-local memory map from Limine entries.
460    // Keep only the first MAX_BOOT_MEMORY_REGIONS entries to avoid dynamic allocation.
461    let (memory_map_base, memory_map_size) = if let Some(memory_map_response) =
462        MEMORY_MAP.get_response()
463    {
464        let entries = memory_map_response.entries();
465        let count = core::cmp::min(entries.len(), MAX_BOOT_MEMORY_REGIONS);
466        unsafe {
467            BOOT_MEMORY_MAP_LEN = count;
468            for (i, entry) in entries.iter().take(count).enumerate() {
469                BOOT_MEMORY_MAP[i] = super::entry::MemoryRegion {
470                    base: entry.base,
471                    size: entry.length,
472                    kind: map_limine_region_kind(entry.entry_type),
473                };
474            }
475            (
476                BOOT_MEMORY_MAP.as_ptr() as u64,
477                (BOOT_MEMORY_MAP_LEN * core::mem::size_of::<super::entry::MemoryRegion>()) as u64,
478            )
479        }
480    } else {
481        (0, 0)
482    };
483
484    // Resolve loaded modules by exact path, not by index/order.
485    // Limine may return modules from config and internal requests in any order.
486    let (
487        fallback_elf_base,
488        fallback_elf_size,
489        ext4_base,
490        ext4_size,
491        ram_base,
492        ram_size,
493    ) = if let Some(
494        module_response,
495    ) =
496        MODULES.get_response()
497    {
498        let modules = module_response.modules();
499        crate::serial_println!("[limine] modules reported: {}", modules.len());
500        for (idx, module) in modules.iter().enumerate() {
501            #[cfg(feature = "selftest")]
502            {
503                let raw_addr = module.addr() as u64;
504                let phys_addr = module_addr_to_phys(raw_addr, hhdm_offset);
505                let (m0, m1, m2, m3) = if module.size() >= 4 {
506                    unsafe {
507                        let p = raw_addr as *const u8;
508                        (
509                            core::ptr::read_volatile(p),
510                            core::ptr::read_volatile(p.add(1)),
511                            core::ptr::read_volatile(p.add(2)),
512                            core::ptr::read_volatile(p.add(3)),
513                        )
514                    }
515                } else {
516                    (0, 0, 0, 0)
517                };
518                crate::serial_println!(
519                        "[limine] module[{}]: path='{}' addr={:#x} phys={:#x} magic={:02x}{:02x}{:02x}{:02x} size={}",
520                        idx,
521                        module.path().to_string_lossy(),
522                        raw_addr,
523                        phys_addr,
524                        m0,
525                        m1,
526                        m2,
527                        m3,
528                        module.size()
529                    );
530            }
531            #[cfg(not(feature = "selftest"))]
532            {
533                crate::serial_println!(
534                    "[limine] module[{}]: path='{}' size={}",
535                    idx,
536                    module.path().to_string_lossy(),
537                    module.size()
538                );
539            }
540        }
541        let resolved = resolve_modules_once(modules, hhdm_offset);
542        let (init_base, init_size) = resolved.test_pid.unwrap_or((0, 0));
543        let (test_syscalls_base, test_syscalls_size) = resolved.test_syscalls.unwrap_or((0, 0));
544        let (test_mem_base, test_mem_size) = resolved.test_mem.unwrap_or((0, 0));
545        let (test_mem_stressed_base, test_mem_stressed_size) =
546            resolved.test_mem_stressed.unwrap_or((0, 0));
547        let (ext4_base, ext4_size) = resolved.fs_ext4.unwrap_or((0, 0));
548        let (ram_base, ram_size) = resolved.fs_ram.unwrap_or((0, 0));
549
550        if test_mem_base != 0 && test_mem_size != 0 {
551            unsafe { TEST_MEM_ELF_MODULE = Some((test_mem_base, test_mem_size)) };
552            crate::serial_println!(
553                "[limine] /initfs/test_mem found: base={:#x} size={}",
554                test_mem_base,
555                test_mem_size
556            );
557        } else {
558            crate::serial_println!("[limine] WARN: /initfs/test_mem not found in modules");
559        }
560        if test_syscalls_base != 0 && test_syscalls_size != 0 {
561            unsafe { TEST_SYSCALLS_ELF_MODULE = Some((test_syscalls_base, test_syscalls_size)) };
562            crate::serial_println!(
563                "[limine] /initfs/test_syscalls found: base={:#x} size={}",
564                test_syscalls_base,
565                test_syscalls_size
566            );
567        } else {
568            crate::serial_println!("[limine] WARN: /initfs/test_syscalls not found in modules");
569        }
570        if test_mem_stressed_base != 0 && test_mem_stressed_size != 0 {
571            unsafe {
572                TEST_MEM_STRESSED_ELF_MODULE =
573                    Some((test_mem_stressed_base, test_mem_stressed_size))
574            };
575            crate::serial_println!(
576                "[limine] /initfs/test_mem_stressed found: base={:#x} size={}",
577                test_mem_stressed_base,
578                test_mem_stressed_size
579            );
580        } else {
581            crate::serial_println!("[limine] WARN: /initfs/test_mem_stressed not found in modules");
582        }
583
584        // New modules: init + console-admin
585        if let Some((base, size)) = resolved.init {
586            unsafe { INIT_ELF_MODULE = Some((base, size)) };
587            crate::serial_println!(
588                "[limine] /initfs/init found: base={:#x} size={}",
589                base,
590                size
591            );
592        } else {
593            crate::serial_println!("[limine] WARN: /initfs/init not found in modules");
594        }
595        if let Some((base, size)) = resolved.console_admin {
596            unsafe { CONSOLE_ADMIN_ELF_MODULE = Some((base, size)) };
597            crate::serial_println!(
598                "[limine] /initfs/console-admin found: base={:#x} size={}",
599                base,
600                size
601            );
602        } else {
603            crate::serial_println!("[limine] WARN: /initfs/console-admin not found in modules");
604        }
605        if let Some((base, size)) = resolved.strate_net {
606            unsafe { STRATE_NET_ELF_MODULE = Some((base, size)) };
607            crate::serial_println!(
608                "[limine] /initfs/strate-net found: base={:#x} size={}",
609                base,
610                size
611            );
612        } else {
613            crate::serial_println!("[limine] WARN: /initfs/strate-net not found in modules");
614        }
615        if let Some((base, size)) = resolved.strate_bus {
616            unsafe { STRATE_BUS_ELF_MODULE = Some((base, size)) };
617            crate::serial_println!(
618                "[limine] /initfs/strate-bus found: base={:#x} size={}",
619                base,
620                size
621            );
622        } else {
623            crate::serial_println!("[limine] WARN: /initfs/strate-bus not found in modules");
624        }
625        if let Some((base, size)) = resolved.dhcp_client {
626            unsafe { DHCP_CLIENT_ELF_MODULE = Some((base, size)) };
627            crate::serial_println!(
628                "[limine] /initfs/bin/dhcp-client found: base={:#x} size={}",
629                base,
630                size
631            );
632        } else {
633            crate::serial_println!("[limine] WARN: /initfs/bin/dhcp-client not found in modules");
634        }
635        if let Some((base, size)) = resolved.ping {
636            unsafe { PING_ELF_MODULE = Some((base, size)) };
637            crate::serial_println!(
638                "[limine] /initfs/bin/ping found: base={:#x} size={}",
639                base,
640                size
641            );
642        } else {
643            crate::serial_println!("[limine] WARN: /initfs/bin/ping not found in modules");
644        }
645        if let Some((base, size)) = resolved.telnetd {
646            unsafe { TELNETD_ELF_MODULE = Some((base, size)) };
647            crate::serial_println!(
648                "[limine] /initfs/bin/telnetd found: base={:#x} size={}",
649                base,
650                size
651            );
652        } else {
653            crate::serial_println!("[limine] WARN: /initfs/bin/telnetd not found in modules");
654        }
655        if let Some((base, size)) = resolved.udp_tool {
656            unsafe { UDP_TOOL_ELF_MODULE = Some((base, size)) };
657            crate::serial_println!(
658                "[limine] /initfs/bin/udp-tool found: base={:#x} size={}",
659                base,
660                size
661            );
662        } else {
663            crate::serial_println!("[limine] WARN: /initfs/bin/udp-tool not found in modules");
664        }
665        if let Some((base, size)) = resolved.strate_wasm {
666            unsafe { STRATE_WASM_ELF_MODULE = Some((base, size)) };
667            crate::serial_println!(
668                "[limine] /initfs/strate-wasm found: base={:#x} size={}",
669                base,
670                size
671            );
672        } else {
673            crate::serial_println!("[limine] WARN: /initfs/strate-wasm not found in modules");
674        }
675        if let Some((base, size)) = resolved.strate_webrtc {
676            unsafe { STRATE_WEBRTC_ELF_MODULE = Some((base, size)) };
677            crate::serial_println!(
678                "[limine] /initfs/strate-webrtc found: base={:#x} size={}",
679                base,
680                size
681            );
682        } else {
683            crate::serial_println!("[limine] WARN: /initfs/strate-webrtc not found in modules");
684        }
685        if let Some((base, size)) = resolved.hello_wasm {
686            unsafe { HELLO_WASM_FILE_MODULE = Some((base, size)) };
687            crate::serial_println!(
688                "[limine] /initfs/bin/hello.wasm found: base={:#x} size={}",
689                base,
690                size
691            );
692        } else {
693            crate::serial_println!("[limine] WARN: /initfs/bin/hello.wasm not found in modules");
694        }
695        if let Some((base, size)) = resolved.wasm_test_toml {
696            unsafe { WASM_TEST_TOML_FILE_MODULE = Some((base, size)) };
697            crate::serial_println!(
698                "[limine] /initfs/wasm-test.toml found: base={:#x} size={}",
699                base,
700                size
701            );
702        } else {
703            crate::serial_println!("[limine] WARN: /initfs/wasm-test.toml not found in modules");
704        }
705
706        if init_base == 0 {
707            crate::serial_println!("[limine] WARN: /initfs/test_pid not found in modules");
708        }
709        if ext4_base == 0 {
710            crate::serial_println!("[limine] WARN: /initfs/fs-ext4 not found in modules");
711        }
712        if ram_base == 0 {
713            crate::serial_println!("[limine] WARN: /initfs/strate-fs-ramfs not found in modules");
714        }
715        (
716            init_base, init_size, ext4_base, ext4_size, ram_base, ram_size,
717        )
718    } else {
719        (0u64, 0u64, 0u64, 0u64, 0u64, 0u64)
720    };
721
722    if ext4_base != 0 && ext4_size != 0 {
723        // SAFETY: set once during early boot.
724        unsafe {
725            FS_EXT4_MODULE = Some((ext4_base, ext4_size));
726        }
727    }
728
729    if ram_base != 0 && ram_size != 0 {
730        // SAFETY: set once during early boot.
731        unsafe {
732            STRATE_FS_RAMFS_MODULE = Some((ram_base, ram_size));
733        }
734    }
735
736    let args = super::entry::KernelArgs {
737        magic: strat9_abi::boot::STRAT9_BOOT_MAGIC,
738        abi_version: strat9_abi::boot::STRAT9_BOOT_ABI_VERSION,
739        kernel_base: EXECUTABLE_ADDRESS
740            .get_response()
741            .map(|r| r.physical_base())
742            .unwrap_or(0x100000),
743        kernel_size: EXECUTABLE_FILE
744            .get_response()
745            .map(|r| r.file().size())
746            .unwrap_or(0),
747        stack_base: 0x80000,
748        stack_size: 0x10000,
749        env_base: 0,
750        env_size: 0,
751        acpi_rsdp_base: rsdp_addr,
752        acpi_rsdp_size: if rsdp_addr != 0 { 36 } else { 0 },
753        memory_map_base,
754        memory_map_size,
755        initfs_base: fallback_elf_base,
756        initfs_size: fallback_elf_size,
757        framebuffer_addr: fb_addr,
758        framebuffer_width: fb_width,
759        framebuffer_height: fb_height,
760        framebuffer_stride: fb_stride,
761        framebuffer_bpp: fb_bpp,
762        framebuffer_red_mask_size: fb_red_mask_size,
763        framebuffer_red_mask_shift: fb_red_mask_shift,
764        framebuffer_green_mask_size: fb_green_mask_size,
765        framebuffer_green_mask_shift: fb_green_mask_shift,
766        framebuffer_blue_mask_size: fb_blue_mask_size,
767        framebuffer_blue_mask_shift: fb_blue_mask_shift,
768        _padding1: 0,
769        hhdm_offset,
770    };
771
772    // Call kernel main
773    crate::kernel_main(&args as *const _);
774}