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