Skip to main content

strat9_kernel/
lib.rs

1//! Strat9-OS Kernel (Bedrock)
2//!
3//! A minimal microkernel handling:
4//! - Scheduling
5//! - IPC (Inter-Process Communication)
6//! - Memory primitives
7//! - Interrupt routing
8//!
9//! Everything else runs as userspace component servers.
10
11#![no_std]
12#![no_main]
13#![feature(abi_x86_interrupt)]
14#![feature(allocator_api)]
15#![feature(alloc_error_handler)]
16
17extern crate alloc;
18
19// OSTD-like abstraction layer (minimal unsafe TCB)
20pub mod ostd;
21
22pub mod acpi;
23pub mod arch;
24pub mod audit;
25pub mod boot;
26pub mod capability;
27pub mod components;
28pub mod hardware;
29pub mod ipc;
30pub mod memory;
31pub mod namespace;
32pub mod process;
33pub mod shell;
34pub mod silo;
35pub mod sync;
36pub mod syscall;
37pub mod trace;
38pub mod vfs;
39
40// Re-export boot::limine::kmain as the main entry point
41pub use boot::limine::kmain;
42
43// serial_print! and serial_println! macros are #[macro_export]'ed
44// from arch::x86_64::serial and available at crate root automatically.
45
46/// Initialize serial output
47pub fn init_serial() {
48    arch::x86_64::serial::init();
49}
50
51/// Initialize the logger (uses serial)
52pub fn init_logger() {
53    boot::logger::init();
54}
55
56/// Initialize kernel components using the component system
57///
58/// This function initializes all kernel components in the correct order
59/// based on their dependencies and priorities.
60pub fn init_components(stage: component::InitStage) -> Result<(), component::ComponentInitError> {
61    component::init_all(stage)
62}
63
64use core::panic::PanicInfo;
65
66const PAGE_SIZE: u64 = 4096;
67const MAX_BOOT_MMAP_REGIONS_WORK: usize = 1024;
68
69/// Performs the null region operation.
70const fn null_region() -> boot::entry::MemoryRegion {
71    boot::entry::MemoryRegion {
72        base: 0,
73        size: 0,
74        kind: boot::entry::MemoryKind::Reserved,
75    }
76}
77
78/// Performs the align down operation.
79#[inline]
80const fn align_down(value: u64, align: u64) -> u64 {
81    value & !(align - 1)
82}
83
84/// Performs the align up operation.
85#[inline]
86const fn align_up(value: u64, align: u64) -> u64 {
87    (value + align - 1) & !(align - 1)
88}
89
90/// Performs the virt or phys to phys operation.
91#[inline]
92const fn virt_or_phys_to_phys(addr: u64, hhdm: u64) -> u64 {
93    if hhdm != 0 && addr >= hhdm {
94        addr - hhdm
95    } else {
96        addr
97    }
98}
99
100/// Performs the reserve range in map operation.
101fn reserve_range_in_map(
102    map: &mut [boot::entry::MemoryRegion],
103    len: &mut usize,
104    reserve_start: u64,
105    reserve_end: u64,
106) {
107    if reserve_start >= reserve_end {
108        return;
109    }
110
111    let mut i = 0usize;
112    while i < *len {
113        let region = map[i];
114        if !matches!(
115            region.kind,
116            boot::entry::MemoryKind::Free | boot::entry::MemoryKind::Reclaim
117        ) {
118            i += 1;
119            continue;
120        }
121
122        let region_start = region.base;
123        let region_end = region.base.saturating_add(region.size);
124        if reserve_end <= region_start || reserve_start >= region_end {
125            i += 1;
126            continue;
127        }
128
129        let overlap_start = core::cmp::max(region_start, reserve_start);
130        let overlap_end = core::cmp::min(region_end, reserve_end);
131
132        if overlap_start <= region_start && overlap_end >= region_end {
133            map[i].kind = boot::entry::MemoryKind::Reserved;
134            i += 1;
135            continue;
136        }
137
138        if overlap_start <= region_start {
139            map[i].base = overlap_end;
140            map[i].size = region_end.saturating_sub(overlap_end);
141            i += 1;
142            continue;
143        }
144
145        if overlap_end >= region_end {
146            map[i].size = overlap_start.saturating_sub(region_start);
147            i += 1;
148            continue;
149        }
150
151        let left = boot::entry::MemoryRegion {
152            base: region_start,
153            size: overlap_start.saturating_sub(region_start),
154            kind: region.kind,
155        };
156        let right = boot::entry::MemoryRegion {
157            base: overlap_end,
158            size: region_end.saturating_sub(overlap_end),
159            kind: region.kind,
160        };
161
162        if *len + 1 > map.len() {
163            map[i] = left;
164            i += 1;
165            continue;
166        }
167
168        for j in (i + 1..*len).rev() {
169            map[j + 1] = map[j];
170        }
171        map[i] = left;
172        map[i + 1] = right;
173        *len += 1;
174        i += 2;
175    }
176}
177
178/// Performs the region kind for addr operation.
179#[cfg(feature = "selftest")]
180fn region_kind_for_addr(
181    map: &[boot::entry::MemoryRegion],
182    len: usize,
183    addr: u64,
184) -> Option<boot::entry::MemoryKind> {
185    map.iter().take(len).find_map(|r| {
186        let start = r.base;
187        let end = r.base.saturating_add(r.size);
188        if addr >= start && addr < end {
189            Some(r.kind)
190        } else {
191            None
192        }
193    })
194}
195
196/// Kernel panic handler
197#[panic_handler]
198fn panic_handler(info: &PanicInfo) -> ! {
199    boot::panic::panic_handler(info)
200}
201
202/// Performs the register initfs module operation.
203fn register_initfs_module(path: &str, module: Option<(u64, u64)>) {
204    let Some((base, size)) = module else {
205        return;
206    };
207    if base == 0 || size == 0 {
208        return;
209    }
210
211    let base_virt = memory::phys_to_virt(base) as *const u8;
212    let len = size as usize;
213    #[cfg(feature = "selftest")]
214    {
215        // Only peek small header bytes for debugging; no heap allocations.
216        let data = unsafe { core::slice::from_raw_parts(base_virt, len.min(4)) };
217        if data.len() == 4 {
218            serial_println!(
219                "[init] /initfs/{} source magic={:02x}{:02x}{:02x}{:02x} size={}",
220                path,
221                data[0],
222                data[1],
223                data[2],
224                data[3],
225                size
226            );
227        }
228    }
229
230    // Register the bootloader-provided module directly; keep it read-only.
231    if let Err(e) = vfs::register_initfs_file(path, base_virt, len) {
232        serial_println!("[init] Failed to register /initfs/{}: {:?}", path, e);
233    } else {
234        serial_println!("[init] Registered /initfs/{} ({} bytes)", path, size);
235    }
236}
237
238/// Performs the register boot initfs modules operation.
239fn register_boot_initfs_modules(initfs_base: u64, initfs_size: u64) {
240    let boot_test_pid = if initfs_base != 0 && initfs_size != 0 {
241        Some((initfs_base, initfs_size))
242    } else {
243        None
244    };
245    let initfs_modules = [
246        ("test_pid", boot_test_pid),
247        ("test_syscalls", crate::boot::limine::test_syscalls_module()),
248        ("test_mem", crate::boot::limine::test_mem_module()),
249        (
250            "test_mem_stressed",
251            crate::boot::limine::test_mem_stressed_module(),
252        ),
253        ("fs-ext4", crate::boot::limine::fs_ext4_module()),
254        (
255            "strate-fs-ramfs",
256            crate::boot::limine::strate_fs_ramfs_module(),
257        ),
258        ("init", crate::boot::limine::init_module()),
259        ("console-admin", crate::boot::limine::console_admin_module()),
260        ("strate-net", crate::boot::limine::strate_net_module()),
261        ("strate-bus", crate::boot::limine::strate_bus_module()),
262        ("bin/dhcp-client", crate::boot::limine::dhcp_client_module()),
263        ("bin/ping", crate::boot::limine::ping_module()),
264        ("bin/telnetd", crate::boot::limine::telnetd_module()),
265        ("bin/udp-tool", crate::boot::limine::udp_tool_module()),
266        ("strate-wasm", crate::boot::limine::strate_wasm_module()),
267        ("strate-webrtc", crate::boot::limine::strate_webrtc_module()),
268        ("bin/hello.wasm", crate::boot::limine::hello_wasm_module()),
269        (
270            "wasm-test.toml",
271            crate::boot::limine::wasm_test_toml_module(),
272        ),
273    ];
274    for (path, module) in initfs_modules {
275        register_initfs_module(path, module);
276    }
277}
278
279/// Performs the boot module slice operation.
280#[inline]
281fn boot_module_slice(base: u64, size: u64) -> &'static [u8] {
282    let base_virt = memory::phys_to_virt(base);
283    unsafe { core::slice::from_raw_parts(base_virt as *const u8, size as usize) }
284}
285
286/// Performs the log boot module magics operation.
287#[cfg(feature = "selftest")]
288fn log_boot_module_magics(stage: &str) {
289    let modules = [
290        ("init", crate::boot::limine::init_module()),
291        ("console-admin", crate::boot::limine::console_admin_module()),
292        ("strate-net", crate::boot::limine::strate_net_module()),
293        ("strate-bus", crate::boot::limine::strate_bus_module()),
294        ("bin/dhcp-client", crate::boot::limine::dhcp_client_module()),
295        ("bin/ping", crate::boot::limine::ping_module()),
296        ("bin/telnetd", crate::boot::limine::telnetd_module()),
297        ("bin/udp-tool", crate::boot::limine::udp_tool_module()),
298        ("strate-wasm", crate::boot::limine::strate_wasm_module()),
299        ("strate-webrtc", crate::boot::limine::strate_webrtc_module()),
300        ("bin/hello.wasm", crate::boot::limine::hello_wasm_module()),
301        (
302            "wasm-test.toml",
303            crate::boot::limine::wasm_test_toml_module(),
304        ),
305    ];
306    for (name, module) in modules {
307        let Some((base, size)) = module else {
308            continue;
309        };
310        if size < 4 {
311            continue;
312        }
313        let ptr = memory::phys_to_virt(base) as *const u8;
314        let m0 = unsafe { core::ptr::read_volatile(ptr) };
315        let m1 = unsafe { core::ptr::read_volatile(ptr.add(1)) };
316        let m2 = unsafe { core::ptr::read_volatile(ptr.add(2)) };
317        let m3 = unsafe { core::ptr::read_volatile(ptr.add(3)) };
318        serial_println!(
319            "[init] Module magic [{}]: {} phys=0x{:x} magic={:02x}{:02x}{:02x}{:02x} size={}",
320            stage,
321            name,
322            base,
323            m0,
324            m1,
325            m2,
326            m3,
327            size
328        );
329    }
330}
331
332/// Performs the log boot module magics operation.
333#[cfg(not(feature = "selftest"))]
334fn log_boot_module_magics(_stage: &str) {}
335
336/// Main kernel initialization - called by bootloader entry points
337pub unsafe fn kernel_main(args: *const boot::entry::KernelArgs) -> ! {
338    // Invariant: interrupts must stay disabled throughout kernel_main until the
339    // scheduler is ready and the APIC timer is started (Asterinas pattern:
340    // interrupts are only enabled once, at the very end of init).
341    debug_assert!(
342        !arch::x86_64::interrupts_enabled(),
343        "interrupts must be disabled at boot entry"
344    );
345
346    // =============================================
347    // Phase 1: serial output (earliest debug output)
348    // =============================================
349    init_serial();
350    init_logger();
351
352    // =============================================
353    // Phase 1c: IDT (Interrupt Descriptor Table)
354    // =============================================
355    // We initialize the IDT as early as possible to catch any exceptions
356    // during the early memory management and hardware initialization phases.
357    serial_println!("[init] IDT (early)...");
358    arch::x86_64::idt::init();
359    serial_println!("[init] IDT initialized.");
360
361    debug_assert!(
362        !arch::x86_64::interrupts_enabled(),
363        "interrupts must be disabled after IDT init"
364    );
365
366    // Detect CPU features (must happen before init_cpu_extensions)
367    crate::arch::x86_64::cpuid::init();
368
369    // Initialize FPU/SSE/XSAVE for the BSP
370    crate::arch::x86_64::init_cpu_extensions();
371
372    // Puts default panic hooks early to ensure
373    //we get useful info on any panics during init.
374    boot::panic::install_default_panic_hooks();
375
376    // Nice logo :D
377    serial_println!();
378    serial_println!();
379    serial_println!(r"          __                 __   ________                         ");
380    serial_println!(r"  _______/  |_____________ _/  |_/   __   \           ____  ______ ");
381    serial_println!(r" /  ___/\   __\_  __ \__  \\   __\____    /  ______  /  _ \/  ___/ ");
382    serial_println!(r" \___ \  |  |  |  | \// __ \|  |    /    /  /_____/ (  <_> )___ \  ");
383    serial_println!(r"/____  > |__|  |__|  (____  /__|   /____/            \____/____  > ");
384    serial_println!(r"     \/                   \/                                   \/  ");
385    serial_println!();
386
387    serial_println!("");
388    serial_println!("=======================================================================================================");
389    serial_println!("  strat9-OS kernel v0.1.0 (Bedrock)");
390    serial_println!("  Copyright (c) 2025-26 Guillaume Gielly - GPLv3 License");
391    serial_println!("");
392    //serial_println!("  GNU General Public License as published by the Free Software Foundation, either version 3 of the ");
393    //serial_println!("  License, or (at your option) any later version.");
394    serial_println!("  This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, without");
395    serial_println!(
396        "  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
397    );
398    serial_println!("  See the GNU General Public License for more details.");
399    serial_println!("=======================================================================================================");
400    serial_println!();
401
402    // Validate arguments
403    if args.is_null() {
404        serial_println!("[CRIT] No KernelArgs provided. System will hang.");
405        loop {
406            arch::x86_64::hlt();
407        }
408    }
409
410    let args = &*args;
411    serial_println!("[init] KernelArgs at {:p}", args);
412
413    if args.magic != strat9_abi::boot::STRAT9_BOOT_MAGIC {
414        serial_println!(
415            "[CRIT] Bad KernelArgs magic: 0x{:08x} (expected 0x{:08x})",
416            args.magic,
417            strat9_abi::boot::STRAT9_BOOT_MAGIC
418        );
419        loop {
420            arch::x86_64::hlt();
421        }
422    }
423    if args.abi_version != strat9_abi::boot::STRAT9_BOOT_ABI_VERSION {
424        serial_println!(
425            "[CRIT] Unsupported boot ABI version: {} (kernel expects {})",
426            args.abi_version,
427            strat9_abi::boot::STRAT9_BOOT_ABI_VERSION
428        );
429        loop {
430            arch::x86_64::hlt();
431        }
432    }
433
434    // Le's go !
435    //
436    // =============================================
437    // Phase 1b : HHDM offset (must be set before any physical memory access)
438    // =============================================
439    let hhdm = args.hhdm_offset;
440    memory::set_hhdm_offset(hhdm);
441    serial_println!("[init] HHDM offset: 0x{:x}", hhdm);
442
443    serial_println!(
444        "[init] Memory map: 0x{:x} ({} bytes)",
445        args.memory_map_base,
446        args.memory_map_size
447    );
448
449    log_boot_module_magics("pre-mm");
450
451    // =============================================
452    // Phase 2 : memory management (Buddy Allocator)
453    // =============================================
454    serial_println!("[init] Memory manager...");
455    let mmap_ptr = args.memory_map_base as *const boot::entry::MemoryRegion;
456    let mmap_len =
457        args.memory_map_size as usize / core::mem::size_of::<boot::entry::MemoryRegion>();
458    let mmap = core::slice::from_raw_parts(mmap_ptr, mmap_len);
459    let mut mmap_work = [null_region(); MAX_BOOT_MMAP_REGIONS_WORK];
460    let mut mmap_work_len = core::cmp::min(mmap.len(), mmap_work.len());
461    for (dst, src) in mmap_work.iter_mut().zip(mmap.iter()).take(mmap_work_len) {
462        *dst = *src;
463    }
464
465    let reserve_modules = [
466        (
467            "test_pid",
468            if args.initfs_base != 0 && args.initfs_size != 0 {
469                Some((args.initfs_base, args.initfs_size))
470            } else {
471                None
472            },
473        ),
474        ("test_syscalls", crate::boot::limine::test_syscalls_module()),
475        ("test_mem", crate::boot::limine::test_mem_module()),
476        (
477            "test_mem_stressed",
478            crate::boot::limine::test_mem_stressed_module(),
479        ),
480        ("fs-ext4", crate::boot::limine::fs_ext4_module()),
481        (
482            "strate-fs-ramfs",
483            crate::boot::limine::strate_fs_ramfs_module(),
484        ),
485        ("init", crate::boot::limine::init_module()),
486        ("console-admin", crate::boot::limine::console_admin_module()),
487        ("strate-net", crate::boot::limine::strate_net_module()),
488        ("strate-bus", crate::boot::limine::strate_bus_module()),
489        ("bin/dhcp-client", crate::boot::limine::dhcp_client_module()),
490        ("bin/ping", crate::boot::limine::ping_module()),
491        ("bin/telnetd", crate::boot::limine::telnetd_module()),
492        ("bin/udp-tool", crate::boot::limine::udp_tool_module()),
493        ("strate-wasm", crate::boot::limine::strate_wasm_module()),
494        ("bin/hello.wasm", crate::boot::limine::hello_wasm_module()),
495        (
496            "wasm-test.toml",
497            crate::boot::limine::wasm_test_toml_module(),
498        ),
499    ];
500
501    for (_name, module) in reserve_modules {
502        let Some((base, size)) = module else {
503            continue;
504        };
505        if size == 0 {
506            continue;
507        }
508        let phys = virt_or_phys_to_phys(base, hhdm);
509        let reserve_start = align_down(phys, PAGE_SIZE);
510        let reserve_end = align_up(phys.saturating_add(size), PAGE_SIZE);
511        reserve_range_in_map(
512            &mut mmap_work,
513            &mut mmap_work_len,
514            reserve_start,
515            reserve_end,
516        );
517        #[cfg(feature = "selftest")]
518        {
519            serial_println!(
520                "[init] Reserved module pages: {} phys=0x{:x}..0x{:x}",
521                _name,
522                reserve_start,
523                reserve_end
524            );
525            let kind = region_kind_for_addr(&mmap_work, mmap_work_len, reserve_start);
526            serial_println!(
527                "[init] Module map kind: {} @0x{:x} => {:?}",
528                _name,
529                reserve_start,
530                kind
531            );
532        }
533    }
534
535    // Here we are
536    // We have the memory map from the bootloader, with all modules reserved.
537    memory::boot_alloc::init_boot_allocator(&mmap_work[..mmap_work_len]);
538    serial_println!("[init] Boot allocator ready.");
539
540    let total_ram = mmap_work[..mmap_work_len]
541        .iter()
542        .filter(|region| {
543            matches!(
544                region.kind,
545                boot::entry::MemoryKind::Free | boot::entry::MemoryKind::Reclaim
546            )
547        })
548        .map(|region| region.base.saturating_add(region.size))
549        .max()
550        .unwrap_or(0);
551
552    {
553        let mut boot_alloc = memory::boot_alloc::get_boot_allocator().lock();
554        memory::frame::init_metadata_array(total_ram, &mut *boot_alloc);
555    }
556    serial_println!("[init] Frame metadata ready.");
557
558    memory::buddy::init_buddy_allocator(&mmap_work[..mmap_work_len]);
559
560    serial_println!("[init] Buddy allocator ready.");
561
562    debug_assert!(
563        !arch::x86_64::interrupts_enabled(),
564        "interrupts must be disabled after buddy allocator init"
565    );
566
567    log_boot_module_magics("post-buddy");
568
569    // =============================================
570    // Phase 2.5: paging / VMM (Must be before Console if FB is not already mapped)
571    // =============================================
572    serial_println!("[init] Paging...");
573    memory::paging::init(hhdm);
574
575    // Map all RAM into HHDM to ensure buddy/heap allocations are accessible.
576    // VMware Limine HHDM may be sparse, causing PF on new heap pages.
577    memory::paging::map_all_ram(&mmap_work[..mmap_work_len]);
578
579    // Framebuffer is often backed by MMIO memory outside RAM (e.g. around 0xFDxxxxxx),
580    // or sometimes at the very end of RAM that might be missed by the bootloader's initial map.
581    // Explicitly map its full range in HHDM for all later graphics access.
582    if args.framebuffer_addr != 0 && args.framebuffer_stride != 0 && args.framebuffer_height != 0 {
583        let fb_phys = if args.framebuffer_addr >= hhdm {
584            args.framebuffer_addr - hhdm
585        } else {
586            args.framebuffer_addr
587        };
588        let fb_size =
589            (args.framebuffer_stride as u64).saturating_mul(args.framebuffer_height as u64);
590        memory::paging::ensure_identity_map_range(fb_phys, fb_size);
591        serial_println!(
592            "[init] Framebuffer mapped: phys=0x{:x} size={} bytes",
593            fb_phys,
594            fb_size
595        );
596    }
597    serial_println!("[init] Paging initialized.");
598
599    // =============================================
600    // Phase 3: console output (VGA or serial fallback)
601    // =============================================
602    serial_println!("[init] Console...");
603    arch::x86_64::vga::init(
604        args.framebuffer_addr,
605        args.framebuffer_width,
606        args.framebuffer_height,
607        args.framebuffer_stride,
608        args.framebuffer_bpp,
609        args.framebuffer_red_mask_size,
610        args.framebuffer_red_mask_shift,
611        args.framebuffer_green_mask_size,
612        args.framebuffer_green_mask_shift,
613        args.framebuffer_blue_mask_size,
614        args.framebuffer_blue_mask_shift,
615    );
616    vga_println!("[OK] Paging initialized");
617    vga_println!("[OK] Serial port initialized");
618    vga_println!("[OK] Memory manager active");
619
620    // =============================================
621    // Phase 4a : TSS (Task State Segment)
622    // =============================================
623    serial_println!("[init] TSS...");
624    vga_println!("[..] Initializing TSS...");
625    arch::x86_64::tss::init();
626    serial_println!("[init] TSS initialized.");
627    vga_println!("[OK] TSS initialized");
628
629    // =============================================
630    // Phase 4b : GDT (global Descriptor Table)
631    // =============================================
632    serial_println!("[init] GDT...");
633    vga_println!("[..] Initializing GDT...");
634    arch::x86_64::gdt::init();
635    serial_println!("[init] GDT initialized.");
636    vga_println!("[OK] GDT loaded (with TSS)");
637
638    // =============================================
639    // Phase 4c: SYSCALL/SYSRET MSR configuration
640    // =============================================
641    serial_println!("[init] SYSCALL/SYSRET...");
642    vga_println!("[..] Initializing SYSCALL/SYSRET...");
643    arch::x86_64::syscall::init();
644    serial_println!("[init] SYSCALL/SYSRET initialized.");
645    vga_println!("[OK] SYSCALL/SYSRET configured");
646
647    // =============================================
648    // Phase 4d: component system - Bootstrap stage
649    // =============================================
650    serial_println!("[init] Components (bootstrap)...");
651    vga_println!("[..] Initializing bootstrap components...");
652    if let Err(e) = component::init_all(component::InitStage::Bootstrap) {
653        serial_println!("[WARN] Some bootstrap components failed: {:?}", e);
654    }
655    serial_println!("[init] Bootstrap components initialized.");
656    vga_println!("[OK] Bootstrap components ready");
657
658    // =============================================
659    // Phase 5: IDT (Interrupt Descriptor Table) - ALREADY INITIALIZED EARLY
660    // =============================================
661    // arch::x86_64::idt::init();
662
663    // =============================================
664    // Phase 5b: paging / VMM - (Moved earlier to prevent PF on VGA init)
665    // =============================================
666    log_boot_module_magics("post-paging");
667
668    // =============================================
669    // Phase 5c: kernel address space
670    // =============================================
671    serial_println!("[init] Kernel address space...");
672    vga_println!("[..] Initializing kernel address space...");
673    memory::address_space::init_kernel_address_space();
674    serial_println!("[init] Kernel address space initialized.");
675    debug_assert!(
676        !arch::x86_64::interrupts_enabled(),
677        "interrupts must be disabled after kernel address space init"
678    );
679    vga_println!("[OK] Kernel address space initialized");
680    log_boot_module_magics("post-kas");
681
682    // =============================================
683    // Phase 5d: virtual file system
684    // =============================================
685    serial_println!("[init] VFS...");
686    vga_println!("[..] Initializing virtual file system...");
687
688    vfs::init();
689
690    serial_println!("[init] VFS initialized.");
691    vga_println!("[OK] VFS initialized");
692    register_boot_initfs_modules(args.initfs_base, args.initfs_size);
693
694    log_boot_module_magics("post-cow");
695
696    // =============================================
697    // Phase 6: ACPI + APIC (with PIC fallback)
698    // =============================================
699    serial_println!("[init] Interrupt controller...");
700    vga_println!("[..] Initializing interrupt controller...");
701
702    // Ensure RSDP is mapped (it might be in unmapped legacy region)
703    memory::paging::ensure_identity_map(args.acpi_rsdp_base);
704
705    let rsdp_virt = memory::phys_to_virt(args.acpi_rsdp_base);
706    let apic_active = init_apic_subsystem(rsdp_virt);
707
708    if !apic_active {
709        // Fallback: legacy PIC + PIT
710        serial_println!("[init] APIC unavailable, falling back to legacy PIC");
711        vga_println!("[..] Falling back to legacy PIC...");
712        arch::x86_64::pic::init(
713            arch::x86_64::pic::PIC1_OFFSET,
714            arch::x86_64::pic::PIC2_OFFSET,
715        );
716        arch::x86_64::pic::disable();
717        arch::x86_64::pic::enable_irq(0); // Timer
718        arch::x86_64::pic::enable_irq(1); // Keyboard
719        serial_println!("[init] Legacy PIC initialized.");
720        vga_println!("[OK] Legacy PIC initialized (IRQ0: timer, IRQ1: keyboard)");
721    } else {
722        serial_println!("[init] APIC subsystem initialized.");
723        vga_println!("[OK] APIC + I/O APIC + APIC timer active");
724    }
725
726    // Initialize TLB shootdown system (SMP safety for COW operations).
727    if apic_active {
728        arch::x86_64::tlb::init();
729        serial_println!("[init] TLB shootdown system initialized.");
730        debug_assert!(
731            !arch::x86_64::interrupts_enabled(),
732            "interrupts must be disabled after TLB init"
733        );
734    }
735
736    // ================================================
737    // Phase 6j: SMP bring-up (AP boot) + per-CPU data
738    // ================================================
739    if apic_active {
740        let bsp_apic_id = arch::x86_64::apic::lapic_id();
741        arch::x86_64::percpu::init_boot_cpu(bsp_apic_id);
742        arch::x86_64::percpu::init_gs_base(0);
743        serial_println!("[init] SMP: booting secondary cores...");
744        vga_println!("[..] SMP: starting APs...");
745
746        match arch::x86_64::smp::init() {
747            Ok(count) => {
748                serial_println!("[init] SMP: {} core(s) online", count);
749                vga_println!("[OK] SMP: {} core(s) online", count);
750            }
751            Err(e) => {
752                serial_println!("[init] SMP init failed: {}", e);
753                vga_println!("[WARN] SMP init failed: {}", e);
754            }
755        }
756    } else {
757        arch::x86_64::percpu::init_boot_cpu(0);
758    }
759
760    // =============================================
761    // Phase 6k: PS/2 mouse driver
762    // =============================================
763    if apic_active {
764        let mouse_ok = arch::x86_64::mouse::init();
765
766        if mouse_ok {
767            serial_println!("[init] PS/2 mouse initialized.");
768            vga_println!("[OK] PS/2 mouse ready");
769        } else {
770            serial_println!("[init] PS/2 mouse not found (optional).");
771        }
772    }
773
774    // =============================================
775    // Phase 7: initialize scheduler
776    // =============================================
777    serial_println!("[init] Initializing scheduler...");
778    vga_println!("[..] Setting up multitasking...");
779    // Print struct layout for crash-site offset analysis (debug build only).
780    crate::process::task::Task::debug_print_layout();
781    process::init_scheduler();
782
783    debug_assert!(
784        !arch::x86_64::interrupts_enabled(),
785        "interrupts must be disabled after scheduler init"
786    );
787
788    // =============================================
789    // Phase 7+: Start timer
790    // =============================================
791    // The BSP timer only starts when the scheduler is ready to handle interrupts.
792    // This is the last point where interrupts are guaranteed disabled on BSP.
793    if apic_active {
794        debug_assert!(
795            !arch::x86_64::interrupts_enabled(),
796            "interrupts must be disabled before APIC timer start"
797        );
798        serial_println!("[init] Starting APIC timer on BSP...");
799        arch::x86_64::timer::start_apic_timer_cached();
800    }
801
802    serial_println!("[init] Scheduler initialized.");
803    serial_println!("[trace][bsp] after init_scheduler");
804    vga_println!("[OK] Multitasking enabled");
805
806    // =============================================
807    // Phase 7b: component system - Kthread stage
808    // =============================================
809    serial_println!("[trace][bsp] before kthread init_all");
810    serial_println!("[init] Components (kthread)...");
811    vga_println!("[..] Initializing kthread components...");
812
813    if let Err(e) = component::init_all(component::InitStage::Kthread) {
814        serial_println!("[WARN] Some kthread components failed: {:?}", e);
815    }
816
817    serial_println!("[trace][bsp] after kthread init_all");
818    serial_println!("[init] Kthread components initialized.");
819    vga_println!("[OK] Kthread components ready");
820
821    #[cfg(feature = "selftest")]
822    {
823        // =============================================
824        // Phase 8a: runtime self-tests
825        // =============================================
826        serial_println!("[init] Creating self-test tasks...");
827        vga_println!("[..] Adding self-test tasks...");
828        process::selftest::create_selftest_tasks();
829        serial_println!("[init] Self-test tasks created.");
830        vga_println!("[OK] Self-test tasks added");
831    }
832
833    // Ring3 smoke test task disabled in selftest mode: fork-test already
834    // exercises Ring3 transitions and this extra task can interfere.
835
836    #[cfg(not(feature = "selftest"))]
837    {
838        // =============================================
839        // Phase 8c: process components
840        // =============================================
841        let mut init_task_id: Option<crate::process::TaskId> = None;
842
843        serial_println!("[init] Components (process)...");
844        vga_println!("[..] Initializing process components...");
845        if let Err(e) = component::init_all(component::InitStage::Process) {
846            serial_println!("[WARN] Some process components failed: {:?}", e);
847        }
848        serial_println!("[init] Process components initialized.");
849        vga_println!("[OK] Process components ready");
850
851        // =============================================
852        // Phase 8d: VirtIO + hardware drivers
853        // =============================================
854        // Blocking launch order note:
855        // PCI consumers now rely on /bus/pci/* exposed by userspace strate-bus.
856        // The userspace boot sequence must start silo "bus" before PCI-dependent
857        // silos, otherwise early probes can legitimately return no device.
858        serial_println!("[init] Loading hardware drivers...");
859        vga_println!("[..] Initializing hardware drivers...");
860        hardware::init();
861
862        serial_println!("[init] Initializing timers...");
863        vga_println!("[..] Initializing HPET and RTC...");
864        hardware::timer::init();
865        serial_println!("[init] Timers initialized.");
866        vga_println!("[OK] HPET/RTC initialized");
867
868        serial_println!("[init] Initializing USB...");
869        vga_println!("[..] Looking for USB controllers...");
870        hardware::usb::init();
871        serial_println!("[init] USB initialized.");
872        vga_println!("[OK] USB xHCI/EHCI/UHCI initialized");
873
874        serial_println!("[init] Initializing VirtIO block...");
875        vga_println!("[..] Looking for VirtIO block device...");
876        hardware::storage::virtio_block::init();
877        serial_println!("[init] VirtIO block initialized.");
878        vga_println!("[OK] VirtIO block driver initialized");
879
880        serial_println!("[init] Initializing AHCI...");
881        vga_println!("[..] Looking for AHCI SATA controller...");
882        hardware::storage::ahci::init();
883        serial_println!("[init] AHCI probe done.");
884        vga_println!("[OK] AHCI probe done");
885
886        serial_println!("[init] Initializing ATA/IDE...");
887        vga_println!("[..] Looking for ATA/IDE devices...");
888        hardware::storage::ata_legacy::init();
889        serial_println!("[init] ATA/IDE probe done.");
890        vga_println!("[OK] ATA/IDE probe done");
891
892        serial_println!("[init] Initializing NVMe...");
893        vga_println!("[..] Looking for NVMe controllers...");
894        hardware::storage::nvme::init();
895        serial_println!("[init] NVMe probe done.");
896        vga_println!("[OK] NVMe probe done");
897
898        serial_println!("[init] Initializing VirtIO net...");
899        vga_println!("[..] Looking for VirtIO net device...");
900        hardware::nic::virtio_net::init();
901        serial_println!("[init] VirtIO net initialized.");
902        vga_println!("[OK] VirtIO net driver initialized");
903
904        serial_println!("[init] Initializing VirtIO RNG...");
905        vga_println!("[..] Looking for VirtIO RNG device...");
906        crate::hardware::virtio::rng::init();
907        serial_println!("[init] VirtIO RNG initialized.");
908        vga_println!("[OK] VirtIO RNG driver initialized");
909
910        serial_println!("[init] Initializing VirtIO Console...");
911        vga_println!("[..] Looking for VirtIO Console device...");
912        crate::hardware::virtio::console::init();
913        serial_println!("[init] VirtIO Console initialized.");
914        vga_println!("[OK] VirtIO Console driver initialized");
915
916        // VirtIO GPU + framebuffer are initialized in hardware::init()
917
918        serial_println!("[init] Checking for devices...");
919        vga_println!("[..] Checking for devices...");
920
921        if let Some(blk) = hardware::storage::virtio_block::get_device() {
922            use hardware::storage::virtio_block::BlockDevice;
923            serial_println!(
924                "[INFO] VirtIO block device found. Capacity: {} sectors",
925                blk.sector_count()
926            );
927            vga_println!("[OK] VirtIO block driver loaded");
928        } else {
929            serial_println!("[WARN] No VirtIO block device found");
930            vga_println!("[WARN] No VirtIO block device found");
931        }
932
933        if let Some(ahci) = hardware::storage::ahci::get_device() {
934            serial_println!(
935                "[INFO] AHCI SATA device found. Capacity: {} sectors ({} MiB)",
936                ahci.sector_count(),
937                (ahci.sector_count() * 512) / 1048576, // 1024*1024 bytes per MiB, 512 bytes per sector
938            );
939            vga_println!("[OK] AHCI SATA driver loaded");
940        } else {
941            serial_println!("[INFO] No AHCI SATA device found");
942        }
943
944        if let Some(nvme) = hardware::storage::nvme::get_first_controller() {
945            if let Some(ns) = nvme.get_namespace(0) {
946                serial_println!(
947                    "[INFO] NVMe device found. Namespace {} - {} blocks @ {} bytes ({} MiB)",
948                    ns.nsid,
949                    ns.size,
950                    ns.block_size,
951                    (ns.size * ns.block_size as u64) / 1048576, // 1024*1024 bytes per MiB
952                );
953                vga_println!("[OK] NVMe driver loaded");
954            }
955        } else {
956            serial_println!("[INFO] No NVMe device found");
957        }
958
959        // Report all registered network interfaces (E1000 + VirtIO)
960        {
961            let ifaces = hardware::nic::list_interfaces();
962            if ifaces.is_empty() {
963                serial_println!("[WARN] No network devices found");
964                vga_println!("[WARN] No network devices found");
965            } else {
966                for name in &ifaces {
967                    if let Some(dev) = hardware::nic::get_device(name) {
968                        let mac = dev.mac_address();
969                        serial_println!(
970                            "[INFO] Network {} ({}) MAC {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x} link={}",
971                            name, dev.name(),
972                            mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
973                            if dev.link_up() { "up" } else { "down" },
974                        );
975                        vga_println!("[OK] Network {} ({}) loaded", name, dev.name());
976                    }
977                }
978            }
979        }
980
981        serial_println!("[init] Storage verification skipped (boot path)");
982        vga_println!("[..] Storage verification skipped at boot");
983
984        // Launch the init process: prefer /initfs/init, fall back to /initfs/test_pid.
985        // The fallback is tried both when the primary module is absent AND when it
986        // is present but contains an invalid ELF (corrupt / wrong arch).
987        let mut init_loaded = false;
988
989        if let Some((base, size)) = crate::boot::limine::init_module() {
990            let elf_data = boot_module_slice(base, size);
991            match process::elf::load_and_run_elf(elf_data, "init") {
992                Ok(task_id) => {
993                    init_task_id = Some(task_id);
994                    init_loaded = true;
995                    serial_println!("[init] ELF '/initfs/init' loaded as task 'init'.");
996                }
997                Err(e) => {
998                    serial_println!("[init] Failed to load init ELF: {}; trying fallback.", e);
999                }
1000            }
1001        }
1002
1003        if !init_loaded && args.initfs_base != 0 && args.initfs_size != 0 {
1004            let elf_data = boot_module_slice(args.initfs_base, args.initfs_size);
1005            match process::elf::load_and_run_elf(elf_data, "init") {
1006                Ok(task_id) => {
1007                    init_task_id = Some(task_id);
1008                    serial_println!(
1009                        "[init] ELF '/initfs/test_pid' loaded as task 'init' (fallback)."
1010                    );
1011                }
1012                Err(e) => {
1013                    serial_println!("[init] Failed to load test_pid ELF: {}", e);
1014                }
1015            }
1016        }
1017        if let Some((base, size)) = crate::boot::limine::strate_fs_ramfs_module() {
1018            let ram_data = boot_module_slice(base, size);
1019            match process::elf::load_elf_task_with_caps(ram_data, "strate-fs-ramfs", &[]) {
1020                Ok(task) => {
1021                    let task_id = task.id;
1022                    crate::serial_force_println!(
1023                        "[trace][boot] before register_boot_strate_task tid={} label=ramfs-default",
1024                        task_id.as_u64()
1025                    );
1026                    let reg_res = crate::silo::register_boot_strate_task(task_id, "ramfs-default");
1027                    crate::serial_force_println!(
1028                        "[trace][boot] marker: returned from register_boot_strate_task"
1029                    );
1030                    if let Err(e) = reg_res {
1031                        crate::serial_force_println!(
1032                            "[trace][boot] register_boot_strate_task failed tid={} err={:?}",
1033                            task_id.as_u64(),
1034                            e
1035                        );
1036                    } else {
1037                        crate::serial_force_println!(
1038                            "[trace][boot] register_boot_strate_task ok tid={}",
1039                            task_id.as_u64()
1040                        );
1041                    }
1042                    crate::serial_force_println!(
1043                        "[trace][boot] before add_task tid={} name=strate-fs-ramfs",
1044                        task_id.as_u64()
1045                    );
1046                    process::add_task(task);
1047                    crate::serial_force_println!(
1048                        "[trace][boot] after add_task tid={} name=strate-fs-ramfs",
1049                        task_id.as_u64()
1050                    );
1051                    serial_println!("[init] Component 'strate-fs-ramfs' loaded.");
1052                }
1053                Err(e) => serial_println!("[init] Failed to load strate-fs-ramfs component: {}", e),
1054            }
1055        }
1056        if let Some((base, size)) = crate::boot::limine::fs_ext4_module() {
1057            let ext4_data = boot_module_slice(base, size);
1058            match process::elf::load_elf_task_with_caps(ext4_data, "strate-fs-ext4", &[]) {
1059                Ok(task) => {
1060                    let task_id = task.id;
1061                    crate::serial_force_println!(
1062                        "[trace][boot] before register_boot_strate_task tid={} label=ext4-default",
1063                        task_id.as_u64()
1064                    );
1065                    if let Err(e) = crate::silo::register_boot_strate_task(task_id, "ext4-default")
1066                    {
1067                        crate::serial_force_println!(
1068                            "[trace][boot] register_boot_strate_task failed tid={} err={:?}",
1069                            task_id.as_u64(),
1070                            e
1071                        );
1072                    } else {
1073                        crate::serial_force_println!(
1074                            "[trace][boot] register_boot_strate_task ok tid={}",
1075                            task_id.as_u64()
1076                        );
1077                    }
1078                    crate::serial_force_println!(
1079                        "[trace][boot] before add_task tid={} name=strate-fs-ext4",
1080                        task_id.as_u64()
1081                    );
1082                    process::add_task(task);
1083                    crate::serial_force_println!(
1084                        "[trace][boot] after add_task tid={} name=strate-fs-ext4",
1085                        task_id.as_u64()
1086                    );
1087                    serial_println!("[init] Component 'strate-fs-ext4' loaded.");
1088                }
1089                Err(e) => serial_println!("[init] Failed to load strate-fs-ext4 component: {}", e),
1090            }
1091        }
1092        if let (Some(task_id), Some(device)) =
1093            (init_task_id, hardware::storage::virtio_block::get_device())
1094        {
1095            if let Some(task) = crate::process::get_task_by_id(task_id) {
1096                let cap = crate::capability::get_capability_manager().create_capability(
1097                    crate::capability::ResourceType::Volume,
1098                    device as *const _ as usize,
1099                    crate::capability::CapPermissions {
1100                        read: true,
1101                        write: true,
1102                        execute: false,
1103                        grant: true,
1104                        revoke: true,
1105                    },
1106                );
1107                unsafe { (&mut *task.process.capabilities.get()).insert(cap) };
1108                serial_println!("[init] Granted volume capability to init");
1109            }
1110        }
1111
1112        match process::Task::new_kernel_task_with_stack(
1113            shell::shell_main,
1114            "chevron-shell",
1115            process::TaskPriority::Normal,
1116            64 * 1024,
1117        ) {
1118            Ok(shell_task) => {
1119                process::add_task(shell_task);
1120                serial_println!("[init] Chevron shell ready.");
1121            }
1122            Err(e) => {
1123                serial_println!("[WARN] Failed to create shell task: {}", e);
1124            }
1125        }
1126        if let Ok(status_task) = process::Task::new_kernel_task_with_stack(
1127            arch::x86_64::vga::status_line_task_main,
1128            "status-line",
1129            process::TaskPriority::Low,
1130            64 * 1024,
1131        ) {
1132            process::add_task(status_task);
1133        }
1134    }
1135    #[cfg(feature = "selftest")]
1136    {
1137        serial_println!("[init] Selftest mode: skipping process services and virtio drivers");
1138    }
1139
1140    // Initialize keyboard layout to French by default
1141    crate::arch::x86_64::keyboard_layout::set_french_layout();
1142
1143    // =============================================
1144    // Boot complete — start preemptive multitasking
1145    // =============================================
1146    if apic_active {
1147        arch::x86_64::smp::open_ap_scheduler_gate();
1148    }
1149    serial_println!("[init] Boot complete. Starting preemptive scheduler...");
1150    vga_println!("[OK] Starting multitasking (preemptive)");
1151
1152    // Keep interrupts disabled on the init stack. `schedule_on_cpu()` enters
1153    // the first task with IF=0 and `task_entry_trampoline` executes `sti`
1154    // after the task context is fully installed.
1155
1156    // Start the scheduler - this will never return
1157    process::schedule();
1158}
1159
1160/// Initialize the APIC subsystem (Local APIC + I/O APIC + APIC Timer).
1161///
1162/// Returns `true` if APIC is active, `false` if we should fall back to PIC+PIT.
1163/// On failure at any step, logs a warning and returns `false`.
1164fn init_apic_subsystem(rsdp_vaddr: u64) -> bool {
1165    use arch::x86_64::{apic, ioapic, pic, timer};
1166    use timer::TIMER_HZ;
1167
1168    // Step 6a: check CPUID for APIC support
1169    if !apic::is_present() {
1170        log::warn!("APIC: not present (CPUID)");
1171        return false;
1172    }
1173    serial_println!("[init]   6a. APIC present (CPUID)");
1174
1175    // Step 6b: initialize ACPI (validate RSDP)
1176    match acpi::init(rsdp_vaddr) {
1177        Ok(true) => {}
1178        Ok(false) => {
1179            log::warn!("APIC: no RSDP from bootloader");
1180            return false;
1181        }
1182        Err(e) => {
1183            log::warn!("APIC: ACPI init failed: {}", e);
1184            return false;
1185        }
1186    }
1187    serial_println!("[init]   6b. ACPI RSDP validated");
1188
1189    // Step 6c: Parse MADT
1190    let madt_info = match acpi::madt::parse_madt() {
1191        Some(info) => info,
1192        None => {
1193            log::warn!("APIC: MADT not found");
1194            return false;
1195        }
1196    };
1197    serial_println!("[init]   6c. MADT parsed");
1198
1199    if let Some(mcfg) = acpi::mcfg::parse_mcfg() {
1200        serial_println!(
1201            "[init]   6c+. MCFG parsed ({} segment(s))",
1202            mcfg.entries.len()
1203        );
1204        for entry in mcfg.entries.iter() {
1205            log::info!(
1206                "ACPI: MCFG seg={} ecam={:#x} buses={}..{} ({} bus(es))",
1207                entry.segment_group,
1208                entry.base_address,
1209                entry.start_bus,
1210                entry.end_bus,
1211                entry.bus_count()
1212            );
1213        }
1214    } else {
1215        serial_println!("[init]   6c+. MCFG not found");
1216    }
1217
1218    // Step 6d: initialize Local APIC
1219    // Ensure Local APIC MMIO is mapped
1220    memory::paging::ensure_identity_map(madt_info.local_apic_address as u64);
1221    apic::init(madt_info.local_apic_address);
1222    serial_println!("[init]   6d. Local APIC initialized");
1223
1224    // Step 6e: initialize first I/O APIC
1225    if madt_info.io_apic_count == 0 {
1226        log::warn!("APIC: no I/O APIC in MADT");
1227        return false;
1228    }
1229    let Some(io_apic_entry) = madt_info.io_apics[0] else {
1230        log::warn!("APIC: MADT I/O APIC entry[0] missing");
1231        return false;
1232    };
1233    // Ensure I/O APIC MMIO is mapped
1234    memory::paging::ensure_identity_map(io_apic_entry.address as u64);
1235    ioapic::init(io_apic_entry.address, io_apic_entry.gsi_base);
1236    serial_println!("[init]   6e. I/O APIC initialized");
1237
1238    // Step 6f: remap PIC to 0x20+ then disable permanently
1239    // Must remap first to avoid stray interrupts at exception vectors (0-31)
1240    pic::init(pic::PIC1_OFFSET, pic::PIC2_OFFSET);
1241    pic::disable_permanently();
1242    serial_println!("[init]   6f. Legacy PIC remapped and disabled");
1243
1244    // Step 6g: route IRQ0 (timer) and IRQ1 (keyboard) via I/O APIC
1245    let lapic_id = apic::lapic_id();
1246    ioapic::route_legacy_irq(0, lapic_id, 0x20, &madt_info.overrides);
1247    ioapic::route_legacy_irq(1, lapic_id, 0x21, &madt_info.overrides);
1248    ioapic::route_legacy_irq(12, lapic_id, 0x2C, &madt_info.overrides);
1249    serial_println!("[init]   6g. IRQ0->vec 0x20, IRQ1->vec 0x21, IRQ12->vec 0x2C routed");
1250
1251    // Step 6h: calibrate APIC timer using PIT channel 2
1252    serial_println!("[init]   6h. Calibrating APIC timer using PIT channel 2...");
1253    serial_println!(
1254        "[timer] ================================ TIMER INIT ================================"
1255    );
1256
1257    let ticks_per_10ms = timer::calibrate_apic_timer();
1258
1259    if ticks_per_10ms == 0 {
1260        log::error!("APIC: timer calibration FAILED");
1261        log::warn!("Falling back to legacy PIT timer at 100Hz");
1262
1263        // Re-enable PIC since APIC timer failed
1264        // (Note: I/O APIC routing is still active for keyboard/timer via PIC vectors)
1265        serial_println!("[timer] APIC calibration failed, initializing PIT fallback...");
1266        timer::init_pit(TIMER_HZ as u32);
1267        serial_println!(
1268            "[timer] PIT initialized at {}Hz ({} ms/tick)",
1269            TIMER_HZ,
1270            1_000 / TIMER_HZ
1271        );
1272        serial_println!("[init]   6h. PIT timer initialized (fallback)");
1273
1274        serial_println!("[timer] ============================= TIMER INIT COMPLETE ============================");
1275        serial_println!("[timer] Mode: PIT (legacy fallback)");
1276        serial_println!("[timer] Frequency: {}Hz", TIMER_HZ);
1277        serial_println!("[timer] Interval: {} ms per tick", 1_000 / TIMER_HZ);
1278        serial_println!(
1279            "[timer] =========================================================================="
1280        );
1281
1282        // Continue with PIT - don't return false
1283        // return false;
1284    } else {
1285        serial_println!("[init]   6h. APIC timer calibrated successfully");
1286
1287        // Step 6i: DO NOT start APIC timer yet. (Asterinas style)
1288        // We will start it only after the scheduler is ready.
1289        // timer::start_apic_timer(ticks_per_10ms);
1290
1291        // Step 6i+: quench legacy PIT to prevent phantom timer interrupts.
1292        timer::stop_pit();
1293        ioapic::mask_legacy_irq(0, &madt_info.overrides);
1294        serial_println!("[init]   6i+. Legacy PIT stopped and masked in IOAPIC");
1295
1296        serial_println!("[timer] ============================= TIMER INIT COMPLETE ============================");
1297        serial_println!("[timer] Mode: APIC (native)");
1298        serial_println!("[timer] Frequency: {}Hz", TIMER_HZ);
1299        serial_println!("[timer] Interval: {} ms per tick", 1_000 / TIMER_HZ);
1300        serial_println!("[timer] Ticks per 10ms: {}", ticks_per_10ms);
1301        serial_println!(
1302            "[timer] =========================================================================="
1303        );
1304    }
1305
1306    true
1307}