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