kernel/main.rs
1//! # Scarlet Kernel
2//!
3//! Scarlet is an operating system kernel written in Rust that implements a transparent ABI
4//! conversion layer for executing binaries across different operating systems and architectures.
5//! The kernel provides a universal container runtime environment with strong isolation capabilities,
6//! comprehensive filesystem support, dynamic linking, and modern graphics capabilities.
7//!
8//! ## Multi-ABI Execution System
9//!
10//! The core innovation of Scarlet is its ability to run binaries from different operating systems
11//! transparently within the same runtime environment:
12//!
13//! ### ABI Module Architecture
14//!
15//! - **Modular ABI Implementation**: Each ABI module implements its own complete syscall interface
16//! using shared kernel APIs, rather than translating between syscalls
17//! - **Binary Detection**: Automatic identification of binary format and target ABI through
18//! ELF header analysis and magic number detection
19//! - **Shared Kernel Resources**: All ABIs operate on common kernel objects (VFS, memory, devices)
20//! ensuring consistent behavior and efficient resource utilization
21//! - **Native Implementation**: Each ABI provides full syscall implementation using underlying
22//! kernel abstractions, enabling complete OS compatibility
23//! - **Dynamic Linking**: Native dynamic linker support for shared libraries and position-independent executables
24//!
25//! ### Supported ABIs
26//!
27//! - **Scarlet Native ABI**: Direct kernel interface with optimal performance, featuring:
28//! - Handle-based resource management with capability-based security
29//! - Modern VFS operations with namespace isolation
30//! - Advanced IPC mechanisms including pipes and event-driven communication
31//! - Container-native filesystem operations
32//! - Dynamic linking support
33//!
34//! - **Linux Compatibility ABI** *(in development)*: Full POSIX syscall implementation
35//! - **xv6 Compatibility ABI** *(in development)*: Educational OS syscall implementation
36//!
37//! ## Container Runtime Environment
38//!
39//! Scarlet provides enterprise-grade containerization features:
40//!
41//! ### Filesystem Isolation
42//!
43//! - **Mount Namespace Isolation**: Per-task filesystem namespaces enabling complete isolation
44//! - **Bind Mount Operations**: Selective resource sharing between containers
45//! - **Overlay Filesystem**: Copy-on-write semantics with whiteout support for efficient layering
46//! - **Device File Management**: Controlled access to hardware through DevFS integration
47//!
48//! ### Resource Management
49//!
50//! - **Handle-Based Security**: Capability-based access control with fine-grained permissions
51//! - **Memory Isolation**: Per-task memory spaces with controlled sharing mechanisms
52//! - **Task Lifecycle Management**: Complete process management with environment variable support
53//! - **IPC Mechanisms**: Pipes, shared memory, and other inter-process communication primitives
54//!
55//! ## Virtual File System v2
56//!
57//! Scarlet implements a modern VFS architecture designed for container environments:
58//!
59//! ### Core Architecture
60//!
61//! - **VfsEntry**: Path hierarchy cache providing fast O(1) path resolution with automatic cleanup
62//! - **VfsNode**: Abstract file entity interface with metadata access and clean downcasting
63//! - **FileSystemOperations**: Unified driver API consolidating all filesystem operations
64//! - **Mount Tree Management**: Hierarchical mount point management with O(log n) resolution
65//!
66//! ### Filesystem Drivers
67//!
68//! - **TmpFS**: High-performance memory-based filesystem with configurable size limits
69//! - **CpioFS**: Read-only CPIO archive filesystem optimized for initramfs and embedded data
70//! - **ext2**: Full ext2 filesystem implementation with complete read/write support for persistent storage
71//! - **FAT32**: Complete FAT32 filesystem implementation with directory and file operations
72//! - **OverlayFS**: Advanced union filesystem with copy-up semantics and whiteout support
73//! - **DevFS**: Device file system providing controlled hardware access
74//!
75//! - **Memory Safety**: Prevention of use-after-free, double-free, and data races at compile time:
76//! - The type system ensures resources are not used after being freed
77//! - Mutable references are exclusive, preventing data races
78//! - Lifetimes ensure references do not outlive the data they point to
79//!
80//! - **Trait-based Abstractions**: Common interfaces for device drivers and subsystems enabling modularity:
81//! - The `BlockDevice` trait defines operations for block-based storage
82//! - The `SerialDevice` trait provides a common interface for UART and console devices
83//! - The `FileSystem` trait provides unified filesystem operations for VFS v2 integration
84//!
85//! ## Boot Process
86//!
87//! Scarlet follows a structured, architecture-agnostic initialization sequence
88//! built around the BootInfo structure for unified system startup:
89//!
90//! ### Architecture-Specific Boot Phase
91//!
92//! 1. **Low-level Initialization**: CPU feature detection, trap vector setup
93//! 2. **Hardware Discovery**: Parse firmware-provided hardware description (FDT/UEFI/ACPI)
94//! 3. **Memory Layout**: Determine usable memory areas and relocate critical data
95//! 4. **BootInfo Creation**: Consolidate boot parameters into unified structure
96//! 5. **Kernel Handoff**: Call `start_kernel()` with complete BootInfo
97//!
98//! ### Unified Kernel Initialization
99//!
100//! 6. **Early Memory Setup**: Heap allocator initialization using BootInfo memory areas
101//! 7. **Early Subsystems**: Critical kernel subsystem initialization via early initcalls
102//! 8. **Driver Framework**: Device driver registration and basic driver initcalls
103//! 9. **Virtual Memory**: Kernel virtual memory management and address space setup
104//! 10. **Device Discovery**: Hardware enumeration from BootInfo device source
105//! 11. **Graphics Subsystem**: Framebuffer and graphics device initialization
106//! 12. **Interrupt Infrastructure**: Interrupt controller setup and handler registration
107//! 13. **Timer Subsystem**: Kernel timer initialization for scheduling and timekeeping
108//! 14. **Virtual File System**: VFS initialization and root filesystem mounting
109//! 15. **Initial Filesystem**: Initramfs processing if provided in BootInfo
110//! 16. **Initial Process**: Create and load first userspace task (/system/scarlet/bin/init)
111//! 17. **Scheduler Activation**: Begin task scheduling and enter normal operation
112//!
113//! ### BootInfo Integration Benefits
114//!
115//! - **Architecture Abstraction**: Unified interface across RISC-V, ARM, x86 platforms
116//! - **Modular Design**: Clean separation between arch-specific and generic initialization
117//! - **Memory Safety**: Structured memory area management prevents overlaps and corruption
118//! - **Extensibility**: Easy addition of new boot parameters without breaking existing code
119//! - **Debugging**: Centralized boot information for diagnostics and troubleshooting
120//!
121//! Each stage validates successful completion before proceeding, with comprehensive
122//! logging available through the early console interface. The BootInfo structure
123//! ensures all necessary information is available throughout the initialization process.
124//!
125//! ## System Integration
126//!
127//! ### Core Subsystems
128//!
129//! - **Task Management**: Complete process lifecycle with environment variables and IPC
130//! - **Memory Management**: Virtual memory with per-task address spaces and shared regions
131//! - **Device Framework**: Unified device interface supporting block, character, and platform devices
132//! - **Interrupt Handling**: Event-driven architecture with proper context switching
133//! - **Handle System**: Capability-based resource access with fine-grained permissions
134//!
135//! ### ABI Module Integration
136//!
137//! Each ABI module integrates with the kernel through standardized interfaces:
138//!
139//! - **Binary Loading**: ELF loader with format detection and validation
140//! - **Syscall Dispatch**: Per-ABI syscall tables with transparent routing
141//! - **Resource Management**: Shared kernel object access through common APIs
142//! - **Environment Setup**: ABI-specific process initialization and cleanup
143//! - **Mount Operations**: `mount()`, `umount()`, `pivot_root()` for dynamic filesystem management
144//! - **Process Management**: `execve()`, `fork()`, `wait()`, `exit()` with proper cleanup
145//! - **IPC Operations**: Pipe creation, communication, and resource sharing
146//!
147//! ## Architecture Support
148//!
149//! Currently implemented for RISC-V 64-bit architecture with comprehensive hardware support:
150//!
151//! - **Interrupt Handling**: Complete trap frame management with timer and external interrupts
152//! - **Memory Management**: Virtual memory with page tables and memory protection
153//! - **SBI Interface**: Supervisor Binary Interface for firmware communication
154//! - **Instruction Abstractions**: RISC-V specific optimizations with compressed instruction support
155//!
156//! ## Rust Language Features
157//!
158//! Scarlet leverages Rust's advanced features for safe and efficient kernel development:
159//!
160//! ### Memory Safety
161//!
162//! - **Zero-cost Abstractions**: High-level constructs compile to efficient machine code
163//! - **Ownership System**: Automatic memory management without garbage collection overhead
164//! - **Lifetime Validation**: Compile-time prevention of use-after-free and dangling pointer errors
165//! - **Borrowing Rules**: Exclusive mutable access prevents data races at compile time
166//! - **No Buffer Overflows**: Array bounds checking and safe pointer arithmetic
167//!
168//! ### Type System Features
169//!
170//! - **Trait-based Design**: Generic programming with zero-cost abstractions for device drivers
171//! - **Pattern Matching**: Exhaustive matching prevents unhandled error cases
172//! - **Option/Result Types**: Explicit error handling without exceptions or null pointer errors
173//! - **Custom Test Framework**: `#[test_case]` attribute for no-std kernel testing
174//! - **Const Generics**: Compile-time array sizing and type-level programming
175//!
176//! ### No-std Environment
177//!
178//! - **Embedded-first Design**: No standard library dependency for minimal kernel footprint
179//! - **Custom Allocators**: Direct control over memory allocation strategies
180//! - **Inline Assembly**: Direct hardware access when needed with type safety
181//! - **Custom Panic Handler**: Controlled kernel panic behavior for debugging
182//! - **Boot-time Initialization**: Static initialization and controlled startup sequence
183//!
184//! ## Development Framework
185//!
186//! ### Testing Infrastructure
187//!
188//! Scarlet provides a comprehensive testing framework designed for kernel development:
189//!
190//! ```rust
191//! #[test_case]
192//! fn test_vfs_operations() {
193//! // Kernel unit tests run in privileged mode
194//! let vfs = VfsManager::new();
195//! // ... test implementation
196//! }
197//! ```
198//!
199//! - **Custom Test Runner**: `#[test_case]` attribute for kernel-specific testing
200//! - **No-std Testing**: Tests run directly in kernel mode without standard library
201//! - **Integration Tests**: Full subsystem testing including multi-ABI scenarios
202//! - **Hardware-in-the-Loop**: Testing on real hardware and QEMU emulation
203//! - **Performance Benchmarks**: Kernel performance measurement and regression testing
204//!
205//! ### Debugging Support
206//!
207//! - **Early Console**: Serial output available from early boot stages
208//! - **Panic Handler**: Detailed panic information with stack traces
209//! - **GDB Integration**: Full debugging support through QEMU's GDB stub
210//! - **Memory Debugging**: Allocation tracking and leak detection
211//! - **Tracing**: Event tracing for performance analysis and debugging
212//!
213//! ### Build System Integration
214//!
215//! The kernel integrates with `cargo-make` for streamlined development:
216//!
217//! - `cargo make build-debug-riscv64` / `cargo make build-debug-aarch64`: Full build with user programs
218//! - `cargo make test-riscv64` / `cargo make test-aarch64`: Run kernel tests
219//! - `cargo make debug-riscv64` / `cargo make debug-aarch64`: Launch kernel with GDB support
220//! - `cargo make run-riscv64` / `cargo make run-aarch64`: Quick development cycle execution
221//!
222//! ## Entry Points
223//!
224//! The kernel provides multiple entry points for different scenarios:
225//!
226//! - **`start_kernel()`**: Main bootstrap processor initialization
227//! - **`start_ap()`**: Application processor startup for multicore systems
228//! - **`test_main()`**: Test framework entry point when built with testing enabled
229//!
230//! ## Module Organization
231//!
232//! Core kernel modules provide focused functionality:
233//!
234//! - **`abi/`**: Multi-ABI implementation modules (Scarlet Native, Linux, xv6)
235//! - **`arch/`**: Architecture-specific code (currently RISC-V 64-bit)
236//! - **`drivers/`**: Hardware device drivers (UART, block devices, VirtIO)
237//! - **`fs/`**: Filesystem implementations and VFS v2 core
238//! - **`task/`**: Task management, scheduling, and process lifecycle
239//! - **`mem/`**: Memory management, allocators, and virtual memory
240//! - **`syscall/`**: System call dispatch and implementation
241//! - **`object/`**: Kernel object system with handle management
242//! - **`interrupt/`**: Interrupt handling and controller support
243//!
244//! *Note: Currently, Scarlet Native ABI is fully implemented. Linux and xv6 ABI support
245//! are under development and will be available in future releases.*
246
247#![no_std]
248#![no_main]
249#![feature(used_with_arg)]
250#![feature(custom_test_frameworks)]
251#![test_runner(crate::test::test_runner)]
252#![reexport_test_harness_main = "test_main"]
253
254pub mod abi;
255pub mod arch;
256pub mod device;
257pub mod drivers;
258pub mod earlycon;
259pub mod environment;
260pub mod executor;
261pub mod fs;
262pub mod initcall;
263pub mod interrupt;
264pub mod ipc;
265pub mod library;
266pub mod mem;
267#[cfg(feature = "network")]
268pub mod network;
269pub mod object;
270pub mod profiler;
271pub mod random;
272pub mod sched;
273pub mod sync;
274pub mod syscall;
275pub mod task;
276pub mod time;
277pub mod timer;
278pub mod traits;
279pub mod vm;
280
281#[cfg(test)]
282pub mod test;
283
284extern crate alloc;
285use alloc::string::ToString;
286use device::manager::{DeviceManager, DriverPriority};
287use environment::PAGE_SIZE;
288use initcall::{call_initcalls, driver::driver_initcall_call, early::early_initcall_call};
289use slab_allocator_rs::MIN_HEAP_SIZE;
290
291use crate::{
292 device::graphics::manager::GraphicsManager,
293 fs::{drivers::initramfs::init_initramfs, vfs_v2::manager::init_global_vfs_manager},
294 interrupt::InterruptManager,
295};
296use arch::get_cpu;
297use core::sync::atomic::{Ordering, fence};
298use mem::{__KERNEL_SPACE_START, allocator::init_heap};
299use sched::scheduler::get_scheduler;
300use task::{elf_loader::load_elf_into_task, new_user_task};
301use timer::get_kernel_timer;
302use vm::{kernel_vm_init, vmem::MemoryArea};
303
304/// A panic handler is required in Rust, this is probably the most basic one possible
305#[cfg(not(test))]
306#[panic_handler]
307fn panic(info: &core::panic::PanicInfo) -> ! {
308 use arch::instruction::idle;
309
310 crate::early_println!("[Scarlet Kernel] panic: {}", info);
311
312 // if let Some(task) = get_scheduler().get_current_task(get_cpu().get_cpuid()) {
313 // task.exit(1); // Exit the task with error code 1
314 // get_scheduler().schedule(get_cpu());
315 // }
316
317 loop {
318 idle();
319 }
320}
321
322/// Represents the source of device information during boot
323///
324/// Different boot protocols provide hardware information through various mechanisms.
325/// This enum captures the source and relevant parameters for device discovery.
326#[derive(Debug, Clone, Copy)]
327pub enum DeviceSource {
328 /// Flattened Device Tree (FDT) source with relocated FDT address
329 /// Used by RISC-V, ARM, and other architectures that support device trees
330 Fdt(usize),
331 /// Unified Extensible Firmware Interface (UEFI) source
332 /// Modern firmware interface providing comprehensive hardware information
333 Uefi,
334 /// Advanced Configuration and Power Interface (ACPI) source
335 /// x86/x86_64 standard for hardware configuration and power management
336 Acpi,
337 /// No device information available
338 /// Fallback when no hardware description is provided by firmware
339 None,
340}
341
342/// Boot information structure containing essential system parameters
343///
344/// This structure is created during the early boot process and contains
345/// all necessary information for kernel initialization. It abstracts
346/// architecture-specific boot protocols into a common interface.
347///
348/// # Architecture Integration
349///
350/// Different architectures populate this structure from their respective
351/// boot protocols:
352/// - **RISC-V**: Created from FDT (Flattened Device Tree) data
353/// - **ARM/AArch64**: Created from FDT or UEFI
354/// - **x86/x86_64**: Created from ACPI tables or legacy BIOS structures
355///
356/// # Usage
357///
358/// The BootInfo is passed to `start_kernel()` as the primary parameter
359/// and provides all essential information needed for kernel initialization:
360///
361/// ```rust
362/// #[no_mangle]
363/// pub extern "C" fn start_kernel(boot_info: &BootInfo) -> ! {
364/// // Use boot_info for system initialization
365/// let memory = boot_info.usable_memory;
366/// let cpu_id = boot_info.cpu_id;
367/// // ...
368/// }
369/// ```
370pub struct BootInfo {
371 /// CPU/Hart ID of the boot processor
372 /// Used for multicore initialization and per-CPU data structures
373 pub cpu_id: usize,
374 /// Number of CPUs detected at runtime (from FDT)
375 /// Used to drive SMP initialization and per-CPU resource sizing
376 pub cpu_count: usize,
377 /// Usable memory area available for kernel allocation
378 /// Excludes reserved regions, firmware areas, and kernel image
379 pub usable_memory: MemoryArea,
380 /// Optional initramfs memory area if available
381 /// Contains initial root filesystem for early userspace programs
382 pub initramfs: Option<MemoryArea>,
383 /// Optional kernel command line parameters
384 /// Boot arguments passed by bootloader for kernel configuration
385 pub cmdline: Option<&'static str>,
386 /// Source of device information for hardware discovery
387 /// Determines how the kernel will enumerate and initialize devices
388 pub device_source: DeviceSource,
389}
390
391impl BootInfo {
392 /// Creates a new BootInfo instance with the specified parameters
393 ///
394 /// # Arguments
395 ///
396 /// * `cpu_id` - ID of the boot processor/hart
397 /// * `usable_memory` - Memory area available for kernel allocation
398 /// * `initramfs` - Optional initramfs memory area
399 /// * `cmdline` - Optional kernel command line parameters
400 /// * `device_source` - Source of device information for hardware discovery
401 ///
402 /// # Returns
403 ///
404 /// A new BootInfo instance containing the specified boot parameters
405 pub fn new(
406 cpu_id: usize,
407 cpu_count: usize,
408 usable_memory: MemoryArea,
409 initramfs: Option<MemoryArea>,
410 cmdline: Option<&'static str>,
411 device_source: DeviceSource,
412 ) -> Self {
413 Self {
414 cpu_id,
415 cpu_count,
416 usable_memory,
417 initramfs,
418 cmdline,
419 device_source,
420 }
421 }
422
423 /// Returns the kernel command line arguments
424 ///
425 /// Provides access to boot parameters passed by the bootloader.
426 /// Returns an empty string if no command line was provided.
427 ///
428 /// # Returns
429 ///
430 /// Command line string slice, or empty string if none available
431 pub fn get_cmdline(&self) -> &str {
432 if let Some(cmdline) = self.cmdline {
433 cmdline
434 } else {
435 ""
436 }
437 }
438
439 /// Returns the initramfs memory area if available
440 ///
441 /// The initramfs contains an initial root filesystem that can be used
442 /// during early boot before mounting the real root filesystem.
443 ///
444 /// # Returns
445 ///
446 /// Optional memory area containing the initramfs data
447 pub fn get_initramfs(&self) -> Option<MemoryArea> {
448 self.initramfs
449 }
450}
451
452/// Main kernel entry point for the boot processor
453///
454/// This function is called by architecture-specific boot code and performs
455/// the complete kernel initialization sequence using information provided
456/// in the BootInfo structure.
457///
458/// # Boot Sequence
459///
460/// The kernel initialization follows this structured sequence:
461///
462/// 1. **Early System Setup**: Extract boot parameters from BootInfo
463/// 2. **Memory Initialization**: Set up heap allocator with usable memory
464/// 3. **Early Initcalls**: Initialize critical early subsystems
465/// 4. **Driver Initcalls**: Load and initialize device drivers
466/// 5. **Virtual Memory**: Set up kernel virtual memory management
467/// 6. **Device Discovery**: Enumerate hardware from BootInfo device source
468/// 7. **Graphics Initialization**: Initialize graphics subsystem and framebuffer
469/// 8. **Interrupt System**: Set up interrupt controllers and handlers
470/// 9. **Timer Subsystem**: Initialize kernel timer and scheduling infrastructure
471/// 10. **VFS Setup**: Initialize virtual filesystem and mount root
472/// 11. **Initramfs Processing**: Mount initramfs if provided in BootInfo
473/// 12. **Initial Task**: Create and load initial userspace process
474/// 13. **Scheduler Start**: Begin task scheduling and enter normal operation
475///
476/// # Architecture Integration
477///
478/// This function is architecture-agnostic and relies on the BootInfo structure
479/// to abstract hardware-specific details. Architecture-specific boot code is
480/// responsible for creating a properly initialized BootInfo before calling
481/// this function.
482///
483/// # Arguments
484///
485/// * `boot_info` - Comprehensive boot information structure containing:
486/// - CPU ID for multicore initialization
487/// - Usable memory area for heap allocation
488/// - Optional initramfs location and size
489/// - Kernel command line parameters
490/// - Device information source (FDT/UEFI/ACPI)
491///
492/// # Memory Layout
493///
494/// The function expects the following memory layout:
495/// - Kernel image loaded and executable
496/// - BootInfo.usable_memory available for allocation
497/// - Hardware description (FDT/ACPI) accessible via device_source
498/// - Optional initramfs data at specified location
499///
500/// # Safety
501///
502/// This function assumes:
503/// - Architecture-specific initialization has completed successfully
504/// - BootInfo contains valid memory areas and addresses
505/// - Basic CPU features (MMU, interrupts) are available
506/// - Memory protection allows kernel operation
507///
508/// # Returns
509///
510/// This function never returns - it transitions to the scheduler and
511/// enters normal kernel operation mode.
512#[unsafe(no_mangle)]
513pub extern "C" fn start_kernel(boot_info: &BootInfo) -> ! {
514 let cpu_id = boot_info.cpu_id;
515 let cpu_count = boot_info.cpu_count;
516
517 early_println!("[Scarlet Kernel] Hello, I'm Scarlet kernel!");
518 early_println!("[Scarlet Kernel] Boot on CPU {}", cpu_id);
519 early_println!("[Scarlet Kernel] Detected {} CPU(s)", cpu_count);
520 /* Use usable memory area from BootInfo */
521 let usable_area = boot_info.usable_memory;
522 early_println!(
523 "[Scarlet Kernel] Usable memory area : {:#x} - {:#x}",
524 usable_area.start,
525 usable_area.end
526 );
527
528 /* Handle initramfs if available in BootInfo */
529 if let Some(initramfs_area) = boot_info.initramfs {
530 early_println!(
531 "[Scarlet Kernel] InitramFS available: {:#x} - {:#x}",
532 initramfs_area.start,
533 initramfs_area.end
534 );
535 // Note: initramfs already relocated by arch-specific boot code
536 } else {
537 early_println!("[Scarlet Kernel] No initramfs found");
538 }
539
540 /* Initialize heap with the usable memory area */
541 early_println!("[Scarlet Kernel] Initializing heap...");
542 let heap_start = (usable_area.start + PAGE_SIZE - 1) & !(PAGE_SIZE - 1);
543 let heap_size = ((usable_area.end - heap_start + 1) / MIN_HEAP_SIZE) * MIN_HEAP_SIZE;
544 let heap_end = heap_start + heap_size - 1;
545 init_heap(MemoryArea::new(heap_start, heap_end));
546
547 fence(Ordering::SeqCst);
548 early_println!(
549 "[Scarlet Kernel] Heap initialized at {:#x} - {:#x}",
550 heap_start,
551 heap_end
552 );
553
554 {
555 let test_vec = alloc::vec::Vec::<u8>::with_capacity(1024);
556 drop(test_vec);
557 early_println!("[Scarlet Kernel] Heap allocation test passed");
558 }
559
560 fence(Ordering::Release);
561
562 /* After this point, we can use the heap */
563 early_initcall_call();
564 fence(Ordering::SeqCst); // Ensure early initcalls are completed before proceeding
565 driver_initcall_call();
566
567 early_println!("[Scarlet Kernel] Initializing Virtual Memory...");
568 let kernel_start = unsafe { &__KERNEL_SPACE_START as *const usize as usize };
569 kernel_vm_init(MemoryArea::new(kernel_start, usable_area.end));
570 /* After this point, we can use the heap and virtual memory */
571 /* We will also be restricted to the kernel address space */
572
573 /* Populate devices from BootInfo device source */
574 early_println!("[Scarlet Kernel] Populating devices...");
575 let device_manager = DeviceManager::get_manager();
576 // Two-phase interrupt bring-up:
577 // 1) Discover critical interrupt controllers (PLIC/CLINT) first.
578 // 2) Initialize interrupt controllers.
579 // 3) Discover remaining devices (which may enable specific IRQ lines).
580 device_manager
581 .populate_devices_from_source(&boot_info.device_source, Some(&[DriverPriority::Critical]));
582 fence(Ordering::SeqCst); // Ensure device population is complete before proceeding
583
584 /* Initialize interrupt controllers (stage 1) */
585 early_println!("[Scarlet Kernel] Initializing interrupt controllers...");
586 InterruptManager::get_manager().init_controllers();
587
588 fence(Ordering::SeqCst); // Ensure interrupt controllers are initialized before proceeding
589
590 /* Initialize NetworkManager before device discovery so protocol layers are ready */
591 #[cfg(feature = "network")]
592 {
593 early_println!("[NetworkManager] Initializing NetworkLayers...");
594 let _network_manager = crate::network::NetworkManager::init();
595 fence(Ordering::SeqCst);
596 }
597
598 /* Discover remaining devices */
599 early_println!("[Scarlet Kernel] Populating remaining devices...");
600 device_manager.populate_devices_from_source(
601 &boot_info.device_source,
602 Some(&[
603 DriverPriority::Core,
604 DriverPriority::Standard,
605 DriverPriority::Late,
606 ]),
607 );
608 fence(Ordering::SeqCst);
609
610 /* After this point, we can use the device manager */
611 /* Serial console also works */
612
613 /* Initialize Graphics Manager and discover graphics devices */
614 early_println!("[Scarlet Kernel] Initializing graphics subsystem...");
615
616 // Add extra safety measures for optimized builds
617 fence(Ordering::SeqCst); // Ensure device population is complete before proceeding
618
619 // Verify that devices are actually registered before attempting graphics initialization
620 let device_count = DeviceManager::get_manager().get_devices_count();
621 early_println!(
622 "[Scarlet Kernel] Found {} devices before graphics initialization",
623 device_count
624 );
625
626 if device_count > 0 {
627 GraphicsManager::get_manager().discover_graphics_devices();
628 } else {
629 early_println!(
630 "[Scarlet Kernel] Warning: No devices found, skipping graphics initialization"
631 );
632 }
633
634 fence(Ordering::SeqCst); // Ensure graphics devices are discovered before proceeding
635
636 #[cfg(test)]
637 test_main();
638
639 /* Initcalls */
640 early_println!("[boot] entering initcalls");
641 call_initcalls();
642 early_println!("[boot] leaving initcalls");
643
644 fence(Ordering::SeqCst); // Ensure all initcalls are completed before proceeding
645
646 /* Enable CPU interrupt reception (stage 2) */
647 println!("[Scarlet Kernel] Enabling CPU interrupts...");
648 InterruptManager::get_manager().enable_cpu_interrupts();
649
650 fence(Ordering::SeqCst); // Ensure interrupt manager is initialized before proceeding
651
652 /* Initialize timer */
653 early_println!("[boot] Initializing timer...");
654 // Initialize timer for the boot CPU (from BootInfo)
655 get_kernel_timer().init(boot_info.cpu_id);
656
657 fence(Ordering::SeqCst); // Ensure timer is initialized before proceeding
658
659 /* Initialize scheduler */
660 early_println!("[boot] Initializing scheduler...");
661 let scheduler = get_scheduler();
662 fence(Ordering::SeqCst); // Ensure scheduler is initialized before proceeding
663
664 /* Initialize global VFS */
665 early_println!("[boot] Initializing global VFS...");
666 let manager = init_global_vfs_manager();
667
668 /* Initialize initramfs from BootInfo if available */
669 if let Some(initramfs_area) = boot_info.initramfs {
670 println!("[Scarlet Kernel] Initializing initramfs from BootInfo...");
671 if let Err(e) = init_initramfs(&manager, initramfs_area) {
672 println!(
673 "[Scarlet Kernel] Warning: Failed to initialize initramfs: {}",
674 e
675 );
676 }
677 } else {
678 println!("[Scarlet Kernel] No initramfs found in BootInfo");
679 }
680
681 fence(Ordering::SeqCst); // Ensure VFS and initramfs are initialized before proceeding
682
683 /* Apply network configuration from cmdline */
684 #[cfg(feature = "network")]
685 {
686 let cmdline = boot_info.get_cmdline();
687 if !cmdline.is_empty() {
688 crate::network::config::apply_cmdline_config(cmdline);
689 }
690 }
691
692 /* Make init task */
693 early_println!("[boot] Creating initial user task...");
694 let mut task = new_user_task("init".to_string(), 0);
695
696 task.init();
697 *task.vfs.write() = Some(manager.clone());
698 task.vfs
699 .read()
700 .as_ref()
701 .unwrap()
702 .set_cwd_by_path("/")
703 .expect("Failed to set initial working directory");
704 let file_obj = match task
705 .vfs
706 .read()
707 .as_ref()
708 .unwrap()
709 .open("/system/scarlet/bin/init", 0)
710 {
711 Ok(kernel_obj) => kernel_obj,
712 Err(e) => {
713 panic!("Failed to open init file: {:?}", e);
714 }
715 };
716 // file_obj is already a KernelObject::File
717 let file_ref = match file_obj.as_file() {
718 Some(file) => file,
719 None => panic!("Failed to get file reference"),
720 };
721
722 match load_elf_into_task(file_ref, &mut task) {
723 Ok(entry_point) => {
724 task.vm_manager.memmaps_iter_with(|maps| {
725 for map in maps {
726 early_println!(
727 "[Scarlet Kernel] Task memory map: {:#x} - {:#x}",
728 map.vmarea.start,
729 map.vmarea.end
730 );
731 }
732 });
733 early_println!(
734 "[Scarlet Kernel] Init ELF loaded with entry point at {:#x}",
735 entry_point
736 );
737 early_println!("[Scarlet Kernel] Successfully loaded init ELF into task");
738 early_println!("[Scarlet Kernel] Adding init task to scheduler...");
739 let cpu_id = get_cpu().get_cpuid();
740 early_println!("[Scarlet Kernel] cpu_id for init task: {}", cpu_id);
741 get_scheduler().add_task(task, cpu_id);
742 early_println!("[Scarlet Kernel] Init task added to scheduler");
743 }
744 Err(e) => early_println!("[Scarlet Kernel] Error loading ELF into task: {:?}", e),
745 }
746
747 early_println!("[Scarlet Kernel] About to fence before scheduler start...");
748 fence(Ordering::SeqCst); // Ensure task is added to scheduler before proceeding
749 early_println!("[Scarlet Kernel] Fence complete; about to print scheduler start...");
750
751 // Use early_println here to avoid any potential console lock issues.
752 early_println!("[Scarlet Kernel] Scheduler will start...");
753 early_println!("[Scarlet Kernel] Calling start_scheduler()...");
754
755 let next_task_id = scheduler.start_scheduler();
756 if let Some(next_task_id) = next_task_id {
757 let next_task = scheduler
758 .get_task_by_id(next_task_id)
759 .expect("First runnable task must exist");
760 crate::arch::first_switch_to_user(next_task);
761 }
762
763 early_println!("[Scarlet Kernel] No runnable task; entering idle loop");
764 loop {
765 crate::arch::instruction::idle();
766 }
767}
768
769#[unsafe(no_mangle)]
770pub extern "C" fn start_ap(cpu_id: usize) {
771 println!("[Scarlet Kernel] CPU {} is up and running", cpu_id);
772
773 loop {}
774}