diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md deleted file mode 100644 index f34e68d..0000000 --- a/ARCHITECTURE.md +++ /dev/null @@ -1,125 +0,0 @@ -# Rust Kernel Architecture - -## Project Structure - -This Rust kernel project is organized as follows: - -``` -rust/ -├── README.md # Project overview and build instructions -├── Cargo.toml # Root workspace configuration -├── Makefile # Build automation -├── src/ -│ └── lib.rs # Top-level kernel library -├── kernel/ # Core kernel crate -│ ├── Cargo.toml -│ └── src/ -│ ├── lib.rs # Main kernel library -│ ├── prelude.rs # Common imports and macros -│ ├── error.rs # Error handling -│ ├── types.rs # Kernel data types -│ ├── memory/ # Memory management -│ ├── sync.rs # Synchronization primitives -│ ├── process.rs # Process management -│ ├── scheduler.rs # Task scheduling -│ ├── device.rs # Device management -│ ├── driver.rs # Driver framework -│ ├── interrupt.rs # Interrupt handling -│ ├── console.rs # Console/logging -│ ├── module.rs # Module system -│ ├── init.rs # Initialization -│ ├── panic.rs # Panic handler -│ └── arch/ # Architecture-specific code -├── modules/ # Loadable kernel modules -│ ├── Cargo.toml -│ └── src/ -│ ├── hello.rs # Hello world module -│ └── test.rs # Test module -├── drivers/ # Device drivers -│ ├── Cargo.toml -│ └── src/ -│ └── dummy.rs # Example dummy driver -└── test.sh # Build and test script -``` - -## Design Philosophy - -This kernel is designed with the following principles: - -1. **Memory Safety**: Leveraging Rust's ownership system to prevent memory bugs -2. **Zero-Cost Abstractions**: High-level APIs without runtime overhead -3. **Modularity**: Clean separation between subsystems -4. **Linux Compatibility**: Similar APIs and concepts where applicable -5. **Modern Design**: Taking advantage of modern language features - -## Key Components - -### Core Kernel (`kernel/`) - -- **Memory Management**: Page allocation, heap management, virtual memory -- **Process Management**: Process and thread abstractions -- **Synchronization**: Spinlocks, mutexes, and other primitives -- **Device Framework**: Generic device and driver abstractions -- **Module System**: Support for loadable kernel modules -- **Error Handling**: Comprehensive error types and Result-based APIs - -### Modules (`modules/`) - -Loadable kernel modules that can extend kernel functionality: -- `hello.rs`: Simple demonstration module -- `test.rs`: Testing and validation module - -### Drivers (`drivers/`) - -Device drivers implementing the kernel driver framework: -- `dummy.rs`: Example driver showing the driver API - -## Architecture Support - -Currently includes basic support for: -- x86_64 (primary target) -- ARM64 (stub) -- RISC-V (stub) - -## Building and Testing - -```bash -# Build everything -make - -# Run tests -make test - -# Check code quality -make clippy fmt-check - -# Run the automated test script -./test.sh -``` - -## Development Status - -This is a foundational implementation demonstrating: -- ✅ Basic kernel structure and organization -- ✅ Memory management framework -- ✅ Module system with examples -- ✅ Driver framework -- ✅ Synchronization primitives -- ✅ Error handling -- ✅ Build system integration - -Areas for future development: -- [ ] Complete memory management implementation -- [ ] Interrupt handling and timers -- [ ] Full scheduler implementation -- [ ] File system support -- [ ] Network stack -- [ ] Hardware abstraction layers -- [ ] Boot loader integration -- [ ] Performance optimization - -## Relationship to Linux Kernel - -This project is inspired by the Linux kernel's Rust infrastructure (`/linux/rust/`) but is designed as a standalone kernel implementation. It demonstrates how modern Rust can be used for systems programming while maintaining the familiar concepts from traditional kernel development. - -The module system and driver framework are designed to be conceptually similar to Linux while taking advantage of Rust's type system for additional safety guarantees. diff --git a/Cargo.toml b/Cargo.toml index e11c0a0..948b75a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "GPL-2.0" [workspace] members = [ "kernel", - "drivers", + "drivers", "modules" ] @@ -19,20 +19,12 @@ kernel = { path = "kernel" } [dependencies] kernel = { path = "kernel" } -[lib] -name = "rust_kernel" -crate-type = ["staticlib", "cdylib"] - -[features] -default = ["alloc", "std"] -alloc = [] -std = [] -no_std = [] - +# Workspace-level profile configuration [profile.dev] panic = "abort" opt-level = 0 debug = true +lto = false [profile.release] panic = "abort" diff --git a/Makefile b/Makefile index e744b22..538c037 100644 --- a/Makefile +++ b/Makefile @@ -66,8 +66,13 @@ clippy: doc: $(CARGO) doc $(CARGO_FLAGS) --no-deps +# Test the kernel +test-kernel: kernel + @echo "Testing kernel functionality" + cd kernel && $(CARGO) test $(CARGO_FLAGS) + # Install (placeholder) install: @echo "Install target not implemented yet" -.PHONY: all kernel modules drivers clean test fmt-check fmt clippy doc install +.PHONY: all kernel modules drivers clean test fmt-check fmt clippy doc test-kernel install diff --git a/README.md b/README.md index ca21eac..db0b601 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,168 @@ # Rust Kernel -A modern, experimental kernel written in Rust, inspired by the Linux kernel architecture and designed for x86_64 systems. +A modern, experimental x86_64 kernel written in Rust with advanced monitoring, diagnostics, and stress testing capabilities. -## Overview - -This project implements a basic operating system kernel in Rust, featuring: - -- **Memory Management**: Page allocation, virtual memory, slab allocator, and buddy allocator -- **Process Management**: Process creation, scheduling, context switching, and signal handling -- **File System**: Virtual File System (VFS) with ramfs, procfs, and devfs implementations -- **Device Management**: Advanced device driver framework with power management -- **Network Stack**: Basic networking with interface management, ARP, and routing -- **System Calls**: Linux-compatible system call interface -- **Interrupt Handling**: x86_64 IDT setup and exception handling -- **Boot Process**: Staged hardware initialization and kernel setup - -## Architecture - -The kernel is organized into the following main components: +## Features ### Core Systems -- `lib.rs` - Main kernel entry point and module declarations -- `prelude.rs` - Common imports and essential types -- `error.rs` - Kernel error types and errno mappings -- `types.rs` - Fundamental kernel data types (PIDs, UIDs, device IDs, etc.) +- **Memory Management**: Page allocation, kmalloc/vmalloc, physical/virtual memory mapping +- **Process Management**: Basic process structures, kernel threads, scheduling framework +- **File System**: In-memory file system (memfs) with shell integration +- **Device Drivers**: PS/2 keyboard, serial console, basic device framework +- **Network Stack**: Basic networking with loopback interface and statistics +- **Module System**: Dynamic module loading with dependency management +- **System Calls**: Basic syscall infrastructure and user mode support -### Memory Management (`memory/`) -- `page.rs` - Physical page frame allocation and management -- `allocator.rs` - High-level memory allocation interfaces -- `kmalloc.rs` - Kernel memory allocation (slab allocator) -- `vmalloc.rs` - Virtual memory allocation and VMA tracking -- `page_table.rs` - Page table management and virtual memory mapping +### Advanced Features +- **System Diagnostics**: Real-time health monitoring with categorized diagnostics +- **Performance Monitoring**: Comprehensive performance counters and analysis +- **Stress Testing**: Memory, CPU, and filesystem stress testing with metrics +- **Advanced Logging**: Multi-level logging with filtering and statistics +- **System Information**: Detailed hardware detection and system reporting +- **Interactive Shell**: 20+ commands for system administration and testing -### Process Management -- `process.rs` - Process and thread structures, fork/exec/wait/exit -- `scheduler.rs` - Process scheduling and task switching -- `task.rs` - Task management and process lists +### Architecture Support +- **x86_64**: Complete support with GDT, IDT, paging, and exception handling +- **Boot Process**: Multiboot-compatible with staged initialization +- **Hardware Detection**: CPUID-based CPU information and feature detection -### File System (`fs/`) -- `mod.rs` - VFS core and file system registration -- `file.rs` - File descriptor management and operations -- `inode.rs` - Inode operations and metadata -- `dentry.rs` - Directory entry cache -- `super_block.rs` - File system superblock management -- `ramfs.rs` - RAM-based file system implementation -- `procfs.rs` - Process information file system -- `devfs.rs` - Device file system +## Quick Start -### Device Management +### Prerequisites +- Rust nightly toolchain +- NASM assembler +- Make +- QEMU (for testing) + +### Building +```bash +# Build the kernel +make kernel + +# Build in debug mode +RUSTFLAGS="-Awarnings" make kernel + +# Clean build artifacts +make clean +``` + +### Project Structure +``` +├── kernel/ # Core kernel implementation +│ ├── src/ +│ │ ├── lib.rs # Kernel entry point +│ │ ├── arch/ # Architecture-specific code (x86_64) +│ │ ├── memory/ # Memory management subsystem +│ │ ├── fs/ # File system implementation +│ │ └── ... # Other subsystems +├── drivers/ # Device drivers +├── modules/ # Loadable kernel modules +└── src/ # Top-level crate wrapper +``` + +## Shell Commands + +The kernel includes an interactive shell with comprehensive system administration commands: + +### System Information +- `info` - Basic system information +- `sysinfo [show|compact|benchmark]` - Detailed system information +- `mem` - Memory statistics +- `uptime` - System uptime + +### Diagnostics and Health +- `diag [report|check|clear|critical]` - System diagnostics +- `health [status|check|monitor]` - Health monitoring +- `stress [duration]` - Stress testing (memory, cpu, filesystem, all) + +### Performance Monitoring +- `perf [report|clear|counters|reset]` - Performance monitoring +- `bench [list|run|all|stress]` - Built-in benchmarks +- `log [show|clear|level|stats]` - Advanced logging + +### File System +- `ls [path]` - List directory contents +- `cat ` - Display file contents +- `mkdir ` - Create directory +- `touch ` - Create file +- `rm ` - Remove file/directory + +### Development +- `test [all|memory|fs|module]` - Run kernel tests +- `mod [list|test|unload]` - Module management +- `exec ` - Execute user programs +- `clear` - Clear screen +- `help` - Show all commands + +## Key Features + +### System Diagnostics +- Real-time health monitoring with automatic issue detection +- Categorized diagnostics (Memory, CPU, I/O, Network, FileSystem, Process, Kernel) +- Historical tracking with timestamps for trend analysis +- Critical issue alerts with detailed reporting + +### Stress Testing +- **Memory Tests**: Rapid allocation/deallocation with leak detection +- **CPU Tests**: Intensive calculations for performance validation +- **Filesystem Tests**: File operations stress testing +- Performance metrics: operations/second, error rates, duration tracking + +### Performance Monitoring +- Comprehensive performance counters +- Real-time system metrics +- Benchmark suite for system validation +- Integration with stress testing for performance analysis + +### Advanced Logging +- Multi-level logging (debug, info, warn, error) +- Structured log entries with timestamps +- Filtering and search capabilities +- Statistics and analysis tools + +## Development + +### Architecture +The kernel follows a modular design with clear separation of concerns: + +- **Core**: Essential kernel functionality and initialization +- **Memory**: Physical/virtual memory management with allocators +- **Process**: Process management and kernel threading +- **FileSystem**: VFS with in-memory implementation +- **Devices**: Driver framework with basic hardware support +- **Network**: Basic networking stack with interface management +- **Shell**: Interactive command interface for administration + +### Error Handling +Robust error handling throughout with: +- Structured error types with detailed information +- Result-based error propagation +- Diagnostic integration for automatic issue tracking +- Recovery mechanisms where possible + +### Testing +Comprehensive testing framework including: +- Unit tests for individual components +- Integration tests for subsystem interaction +- Stress tests for reliability validation +- Performance benchmarks for optimization + +## License + +SPDX-License-Identifier: GPL-2.0 + +This project is licensed under the GNU General Public License v2.0. + +## Contributing + +This is an experimental kernel project for research and educational purposes. +Contributions are welcome through pull requests and issue reports. + +## Status + +**Experimental** - This kernel is in active development and not suitable for production use. +It serves as a platform for operating system research, Rust kernel development, +and educational purposes. - `device.rs` - Basic device abstraction - `device_advanced.rs` - Advanced device driver framework with power management - `driver.rs` - Device driver registration and management diff --git a/drivers/src/dummy.rs b/drivers/src/dummy.rs deleted file mode 100644 index 92ce10f..0000000 --- a/drivers/src/dummy.rs +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Dummy device driver - -#![no_std] -#![no_main] - -use kernel::prelude::*; -use kernel::driver::{Driver, DriverOps}; -use kernel::device::{Device, DeviceType}; - -struct DummyDriver { - name: &'static str, -} - -impl DummyDriver { - fn new() -> Self { - Self { - name: "dummy_driver", - } - } -} - -impl Driver for DummyDriver { - fn name(&self) -> &str { - self.name - } - - fn probe(&self, device: &mut Device) -> Result<()> { - info!("DummyDriver: probing device {}", device.name); - Ok(()) - } - - fn remove(&self, device: &mut Device) -> Result<()> { - info!("DummyDriver: removing device {}", device.name); - Ok(()) - } -} - -impl DriverOps for DummyDriver { - fn read(&self, offset: u64, buffer: &mut [u8]) -> Result { - info!("DummyDriver: read at offset {} for {} bytes", offset, buffer.len()); - // Fill buffer with dummy data - for (i, byte) in buffer.iter_mut().enumerate() { - *byte = (i % 256) as u8; - } - Ok(buffer.len()) - } - - fn write(&self, offset: u64, buffer: &[u8]) -> Result { - info!("DummyDriver: write at offset {} for {} bytes", offset, buffer.len()); - Ok(buffer.len()) - } - - fn ioctl(&self, cmd: u32, arg: usize) -> Result { - info!("DummyDriver: ioctl cmd={}, arg={}", cmd, arg); - Ok(0) - } -} - -struct DummyModule { - driver: DummyDriver, -} - -impl kernel::module::Module for DummyModule { - fn init(_module: &'static kernel::module::ThisModule) -> Result { - info!("Dummy driver module initializing..."); - - let driver = DummyDriver::new(); - - // Register the driver - kernel::driver::register_driver(Box::new(driver))?; - - info!("Dummy driver registered successfully"); - - Ok(DummyModule { - driver: DummyDriver::new(), - }) - } - - fn exit(_module: &'static kernel::module::ThisModule) { - info!("Dummy driver module exiting"); - // Unregister driver - kernel::driver::unregister_driver("dummy_driver").ok(); - } -} - -module! { - type: DummyModule, - name: "dummy_driver", - author: "Rust Kernel Contributors", - description: "A dummy device driver for testing", - license: "GPL-2.0", -} diff --git a/drivers/src/lib.rs b/drivers/src/lib.rs index cf4b72d..7621ad4 100644 --- a/drivers/src/lib.rs +++ b/drivers/src/lib.rs @@ -8,14 +8,8 @@ extern crate alloc; -pub mod dummy; pub mod mem; -pub mod platform_example; pub mod ramdisk; -pub mod keyboard; // New keyboard driver -pub mod serial; // New serial driver - -pub use dummy::*; -pub use mem::*; -pub use platform_example::*; +pub mod keyboard; // Keyboard driver +pub mod serial; // Serial driver pub use ramdisk::*; diff --git a/drivers/src/platform_example.rs b/drivers/src/platform_example.rs deleted file mode 100644 index 47dd337..0000000 --- a/drivers/src/platform_example.rs +++ /dev/null @@ -1,127 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Platform device driver example - -#![no_std] -#![no_main] - -use kernel::prelude::*; -use kernel::driver::{PlatformDriver, Driver, DeviceId}; -use kernel::device::Device; - -/// Example platform driver -struct ExamplePlatformDriver { - name: &'static str, - device_ids: &'static [DeviceId], -} - -impl ExamplePlatformDriver { - fn new() -> Self { - Self { - name: "example_platform", - device_ids: &[ - DeviceId::new(String::from("example,platform-device")) - .with_compatible(vec![ - String::from("example,platform-device"), - String::from("generic,platform-device"), - ]), - ], - } - } -} - -impl Driver for ExamplePlatformDriver { - fn name(&self) -> &str { - self.name - } - - fn probe(&self, device: &mut Device) -> Result<()> { - info!("Platform driver probing device: {}", device.name()); - - // Initialize device-specific data - device.set_private_data(ExampleDeviceData { - initialized: true, - counter: 0, - }); - - info!("Platform device {} probed successfully", device.name()); - Ok(()) - } - - fn remove(&self, device: &mut Device) -> Result<()> { - info!("Platform driver removing device: {}", device.name()); - - if let Some(data) = device.get_private_data::() { - info!("Device had counter value: {}", data.counter); - } - - Ok(()) - } - - fn suspend(&self, device: &mut Device) -> Result<()> { - info!("Platform device {} suspending", device.name()); - Ok(()) - } - - fn resume(&self, device: &mut Device) -> Result<()> { - info!("Platform device {} resuming", device.name()); - Ok(()) - } - - fn shutdown(&self, device: &mut Device) { - info!("Platform device {} shutting down", device.name()); - } -} - -impl PlatformDriver for ExamplePlatformDriver { - fn match_device(&self, device: &Device) -> bool { - // Simple name-based matching - device.name().contains("example") || device.name().contains("platform") - } - - fn device_ids(&self) -> &[DeviceId] { - self.device_ids - } -} - -/// Device-specific private data -#[derive(Debug)] -struct ExampleDeviceData { - initialized: bool, - counter: u32, -} - -/// Platform driver module -struct PlatformDriverModule { - driver: ExamplePlatformDriver, -} - -impl kernel::module::Module for PlatformDriverModule { - fn init(_module: &'static kernel::module::ThisModule) -> Result { - info!("Platform driver module initializing..."); - - let driver = ExamplePlatformDriver::new(); - - // Register the platform driver - kernel::driver::register_platform_driver(Box::new(driver))?; - - info!("Platform driver registered successfully"); - - Ok(PlatformDriverModule { - driver: ExamplePlatformDriver::new(), - }) - } - - fn exit(_module: &'static kernel::module::ThisModule) { - info!("Platform driver module exiting"); - kernel::driver::unregister_driver("example_platform").ok(); - } -} - -module! { - type: PlatformDriverModule, - name: "example_platform_driver", - author: "Rust Kernel Contributors", - description: "Example platform device driver", - license: "GPL-2.0", -} diff --git a/kernel/.cargo/config.toml b/kernel/.cargo/config.toml new file mode 100644 index 0000000..b2ebe7e --- /dev/null +++ b/kernel/.cargo/config.toml @@ -0,0 +1,6 @@ +[target.x86_64-unknown-none] +rustflags = [ + "-C", "link-arg=-Tlinker.ld", + "-C", "link-arg=--no-dynamic-linker", + "-C", "link-arg=-static", +] diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 2e4600c..34e9759 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -21,3 +21,8 @@ default = [] alloc = [] smp = [] # Symmetric Multi-Processing debug = [] + +[build-dependencies] +cc = "1.0" + +# Profile configuration moved to workspace root diff --git a/kernel/build.rs b/kernel/build.rs new file mode 100644 index 0000000..0027473 --- /dev/null +++ b/kernel/build.rs @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 + +fn main() { + // Build assembly files with rustc + println!("cargo:rerun-if-changed=src/arch/x86_64/boot.s"); + println!("cargo:rerun-if-changed=src/arch/x86_64/exceptions.s"); + println!("cargo:rerun-if-changed=linker.ld"); + + // Tell Cargo to link against the linker script + println!("cargo:rustc-link-arg=-Tlinker.ld"); +} diff --git a/kernel/linker.ld b/kernel/linker.ld new file mode 100644 index 0000000..ffa1230 --- /dev/null +++ b/kernel/linker.ld @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Linker script for Rust Kernel x86_64 */ + +ENTRY(_start) + +SECTIONS +{ + /* Start at 1MB (standard kernel load address) */ + . = 1M; + + /* Multiboot header must be early */ + .multiboot_header : { + *(.multiboot_header) + } + + /* Read-only sections */ + .rodata : ALIGN(4K) { + *(.rodata .rodata.*) + } + + /* Code section */ + .text : ALIGN(4K) { + *(.text .text.*) + } + + /* Read-write data */ + .data : ALIGN(4K) { + *(.data .data.*) + } + + /* BSS section (uninitialized data) */ + .bss : ALIGN(4K) { + *(.bss .bss.*) + *(COMMON) + } + + /* Kernel end marker */ + __kernel_end = .; +} diff --git a/kernel/src/arch/x86_64/boot.s b/kernel/src/arch/x86_64/boot.s new file mode 100644 index 0000000..6bcf58b --- /dev/null +++ b/kernel/src/arch/x86_64/boot.s @@ -0,0 +1,274 @@ +# SPDX-License-Identifier: GPL-2.0 +# Rust Kernel boot entry point for x86_64 + +.section .multiboot_header +header_start: + # Multiboot2 header + .long 0xe85250d6 # magic number + .long 0 # architecture (i386) + .long header_end - header_start # header length + # checksum + .long -(0xe85250d6 + 0 + (header_end - header_start)) + + # end tag + .word 0 # type + .word 0 # flags + .long 8 # size +header_end: + +.section .bss +# Multiboot information storage +.section .bss +multiboot_magic_store: + .skip 4 +# Stack for the kernel +.global stack_bottom +.global stack_top +stack_bottom: + .skip 16384 # 16 KiB stack +stack_top: + +# Bootstrap page tables +.align 4096 +.global boot_page_directory_ptr_table +boot_page_directory_ptr_table: + .skip 4096 + +.global boot_page_directory_table +boot_page_directory_table: + .skip 4096 + +.global boot_page_table +boot_page_table: + .skip 4096 + +.section .rodata +gdt64: + .quad 0 # null descriptor +.set gdt64.code, . - gdt64 + .quad (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53) # code segment +.set gdt64.data, . - gdt64 + .quad (1<<44) | (1<<47) | (1<<41) # data segment +.set gdt64.pointer, . - gdt64 + .word . - gdt64 - 1 # length + .quad gdt64 # address + +.section .text +.global _start +.code32 +_start: + # Set up stack + movl $stack_top, %esp + movl %esp, %ebp + + # Save multiboot information before we lose it + movl %eax, multiboot_magic_store + movl %ebx, multiboot_info_store + + # Check for multiboot + cmpl $0x36d76289, %eax + jne no_multiboot + + # Check for CPUID + call check_cpuid + test %eax, %eax + jz no_cpuid + + # Check for long mode + call check_long_mode + test %eax, %eax + jz no_long_mode + + # Set up page tables for long mode + call setup_page_tables + + # Enable PAE + movl %cr4, %eax + orl $1 << 5, %eax # Set PAE bit + movl %eax, %cr4 + + # Load page table + movl $boot_page_directory_ptr_table, %eax + movl %eax, %cr3 + + # Enable long mode + movl $0xC0000080, %ecx # EFER MSR + rdmsr + orl $1 << 8, %eax # Set LM bit + wrmsr + + # Enable paging + movl %cr0, %eax + orl $1 << 31, %eax # Set PG bit + movl %eax, %cr0 + + # Load GDT + lgdt gdt64.pointer + + # Far jump to 64-bit code + ljmp $gdt64.code, $start64 + +check_cpuid: + # Try to flip the ID bit (bit 21) in FLAGS + pushfl + popl %eax + movl %eax, %ecx + xorl $1 << 21, %eax + pushl %eax + popfl + pushfl + popl %eax + pushl %ecx + popfl + cmpl %ecx, %eax + sete %al + movzbl %al, %eax + ret + +check_long_mode: + # Check if extended processor info is available + movl $0x80000000, %eax + cpuid + cmpl $0x80000001, %eax + jb .no_long_mode + + # Check if long mode is available + movl $0x80000001, %eax + cpuid + testl $1 << 29, %edx + setz %al + movzbl %al, %eax + ret + +.no_long_mode: + xorl %eax, %eax + ret + +setup_page_tables: + # Map first 2MB with 2MB pages + # PDP table entry + movl $boot_page_directory_table, %eax + orl $0b11, %eax # present + writable + movl %eax, boot_page_directory_ptr_table + + # PD table entry + movl $boot_page_table, %eax + orl $0b11, %eax # present + writable + movl %eax, boot_page_directory_table + + # Page table entries (identity map first 2MB) + movl $boot_page_table, %edi + movl $0, %ebx + movl $512, %ecx + +.map_page_table: + movl %ebx, %eax + shll $12, %eax # multiply by 4096 (page size) + orl $0b11, %eax # present + writable + movl %eax, (%edi) + addl $8, %edi + incl %ebx + loop .map_page_table + + ret + +.code64 +start64: + # Set up segment registers + movw $gdt64.data, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + # Set up stack + movq $stack_top, %rsp + + # Clear the screen + call clear_screen + + # Print boot message + movq $boot_msg, %rsi + call print_string + + # Get multiboot parameters from saved locations + movl multiboot_magic_store, %edi # multiboot magic -> first argument + movl multiboot_info_store, %esi # multiboot info -> second argument + + # Call Rust kernel main with multiboot parameters + call kernel_main_multiboot + + # If we get here, halt +halt: + cli + hlt + jmp halt + +# Clear VGA text buffer +clear_screen: + movq $0xb8000, %rdi + movw $0x0f20, %ax # White on black space + movl $2000, %ecx # 80*25 characters + rep stosw + ret + +# Print string to VGA buffer +# RSI = string pointer +print_string: + movq $0xb8000, %rdi + movb $0x0f, %ah # White on black +.print_loop: + lodsb + testb %al, %al + jz .print_done + stosw + jmp .print_loop +.print_done: + ret + +no_multiboot: + movl $no_multiboot_msg, %esi + call print_string_32 + jmp halt32 + +no_cpuid: + movl $no_cpuid_msg, %esi + call print_string_32 + jmp halt32 + +no_long_mode: + movl $no_long_mode_msg, %esi + call print_string_32 + jmp halt32 + +# 32-bit string printing +print_string_32: + movl $0xb8000, %edi + movb $0x4f, %ah # White on red +.print_loop_32: + lodsb + testb %al, %al + jz .print_done_32 + stosw + jmp .print_loop_32 +.print_done_32: + ret + +halt32: + cli + hlt + jmp halt32 + +.section .rodata +boot_msg: + .asciz "Rust Kernel booting..." + +no_multiboot_msg: + .asciz "ERROR: Not loaded by multiboot bootloader" + +no_cpuid_msg: + .asciz "ERROR: CPUID not supported" + +no_long_mode_msg: + .asciz "ERROR: Long mode not supported" diff --git a/kernel/src/arch/x86_64/boot_entry.s b/kernel/src/arch/x86_64/boot_entry.s new file mode 100644 index 0000000..2e625dd --- /dev/null +++ b/kernel/src/arch/x86_64/boot_entry.s @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0 +# Kernel entry point - multiboot compliant + +.section .multiboot +.align 4 + +# Multiboot header +multiboot_header: + .long 0x1BADB002 # Magic number + .long 0x00000003 # Flags (align modules on page boundaries + memory info) + .long -(0x1BADB002 + 0x00000003) # Checksum + +.section .bss +.align 16 +stack_bottom: + .skip 16384 # 16 KB stack +stack_top: + +.section .text +.global _start +.type _start, @function + +_start: + # Set up the stack + mov $stack_top, %esp + + # Reset EFLAGS + pushl $0 + popf + + # Push multiboot parameters + pushl %ebx # Multiboot info structure + pushl %eax # Multiboot magic number + + # Call the kernel main function + call kernel_main_multiboot + + # If kernel returns (shouldn't happen), hang + cli +hang: + hlt + jmp hang + +.size _start, . - _start diff --git a/kernel/src/arch/x86_64/exceptions.s b/kernel/src/arch/x86_64/exceptions.s new file mode 100644 index 0000000..efe8046 --- /dev/null +++ b/kernel/src/arch/x86_64/exceptions.s @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: GPL-2.0 +# Exception handler stubs for x86_64 + +.section .text + +# Macro for exception handlers without error code +.macro EXCEPTION_STUB name, vector +.global \name +\name: + push $0 # Push dummy error code + push $\vector # Push vector number + jmp exception_common +.endm + +# Macro for exception handlers with error code +.macro EXCEPTION_STUB_ERR name, vector +.global \name +\name: + push $\vector # Push vector number (error code already on stack) + jmp exception_common +.endm + +# Exception handlers +EXCEPTION_STUB divide_error_handler, 0 +EXCEPTION_STUB debug_handler, 1 +EXCEPTION_STUB nmi_handler, 2 +EXCEPTION_STUB breakpoint_handler, 3 +EXCEPTION_STUB overflow_handler, 4 +EXCEPTION_STUB bound_range_exceeded_handler, 5 +EXCEPTION_STUB invalid_opcode_handler, 6 +EXCEPTION_STUB device_not_available_handler, 7 +EXCEPTION_STUB_ERR double_fault_handler, 8 +EXCEPTION_STUB_ERR invalid_tss_handler, 10 +EXCEPTION_STUB_ERR segment_not_present_handler, 11 +EXCEPTION_STUB_ERR stack_segment_fault_handler, 12 +EXCEPTION_STUB_ERR general_protection_fault_handler, 13 +EXCEPTION_STUB_ERR page_fault_handler, 14 +EXCEPTION_STUB x87_fpu_error_handler, 16 +EXCEPTION_STUB_ERR alignment_check_handler, 17 +EXCEPTION_STUB machine_check_handler, 18 +EXCEPTION_STUB simd_exception_handler, 19 + +# Common exception handler +exception_common: + # Save all registers + push %rax + push %rcx + push %rdx + push %rbx + push %rbp + push %rsi + push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + + # Save segment registers + mov %ds, %ax + push %rax + mov %es, %ax + push %rax + mov %fs, %ax + push %rax + mov %gs, %ax + push %rax + + # Load kernel data segment + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + # Call exception handler + mov %rsp, %rdi # Pass stack pointer + call exception_handler + + # Restore segment registers + pop %rax + mov %ax, %gs + pop %rax + mov %ax, %fs + pop %rax + mov %ax, %es + pop %rax + mov %ax, %ds + + # Restore all registers + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi + pop %rsi + pop %rbp + pop %rbx + pop %rdx + pop %rcx + pop %rax + + # Remove vector number and error code + add $16, %rsp + + # Return from interrupt + iretq diff --git a/kernel/src/arch/x86_64/gdt.rs b/kernel/src/arch/x86_64/gdt.rs index 7d2cb75..57d7184 100644 --- a/kernel/src/arch/x86_64/gdt.rs +++ b/kernel/src/arch/x86_64/gdt.rs @@ -1,4 +1,152 @@ // SPDX-License-Identifier: GPL-2.0 -//! GDT stub -pub fn init() {} +//! Global Descriptor Table (GDT) for x86_64 + +use core::mem::size_of; + +/// GDT Entry structure +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct GdtEntry { + pub limit_low: u16, + pub base_low: u16, + pub base_middle: u8, + pub access: u8, + pub granularity: u8, + pub base_high: u8, +} + +impl GdtEntry { + pub const fn new() -> Self { + Self { + limit_low: 0, + base_low: 0, + base_middle: 0, + access: 0, + granularity: 0, + base_high: 0, + } + } + + pub fn set_segment(&mut self, base: u32, limit: u32, access: u8, granularity: u8) { + self.base_low = (base & 0xFFFF) as u16; + self.base_middle = ((base >> 16) & 0xFF) as u8; + self.base_high = ((base >> 24) & 0xFF) as u8; + + self.limit_low = (limit & 0xFFFF) as u16; + self.granularity = ((limit >> 16) & 0x0F) as u8 | (granularity & 0xF0); + + self.access = access; + } +} + +/// GDT Pointer structure +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct GdtPointer { + pub limit: u16, + pub base: u64, +} + +/// GDT constants +pub const GDT_ENTRIES: usize = 5; + +/// GDT access byte flags +pub mod access { + pub const PRESENT: u8 = 1 << 7; + pub const RING_0: u8 = 0 << 5; + pub const RING_1: u8 = 1 << 5; + pub const RING_2: u8 = 2 << 5; + pub const RING_3: u8 = 3 << 5; + pub const SYSTEM: u8 = 1 << 4; + pub const EXECUTABLE: u8 = 1 << 3; + pub const CONFORMING: u8 = 1 << 2; + pub const READABLE: u8 = 1 << 1; + pub const WRITABLE: u8 = 1 << 1; + pub const ACCESSED: u8 = 1 << 0; +} + +/// GDT granularity flags +pub mod granularity { + pub const GRANULARITY_4K: u8 = 1 << 7; + pub const SIZE_32: u8 = 1 << 6; + pub const LONG_MODE: u8 = 1 << 5; +} + +/// Global GDT +static mut GDT: [GdtEntry; GDT_ENTRIES] = [GdtEntry::new(); GDT_ENTRIES]; + +/// Initialize GDT +pub fn init() { + unsafe { + // Null descriptor + GDT[0] = GdtEntry::new(); + + // Kernel code segment (64-bit) + GDT[1].set_segment( + 0x00000000, + 0xFFFFF, + access::PRESENT | access::RING_0 | access::SYSTEM | access::EXECUTABLE | access::READABLE, + granularity::GRANULARITY_4K | granularity::LONG_MODE + ); + + // Kernel data segment (64-bit) + GDT[2].set_segment( + 0x00000000, + 0xFFFFF, + access::PRESENT | access::RING_0 | access::SYSTEM | access::WRITABLE, + granularity::GRANULARITY_4K | granularity::LONG_MODE + ); + + // User code segment (64-bit) + GDT[3].set_segment( + 0x00000000, + 0xFFFFF, + access::PRESENT | access::RING_3 | access::SYSTEM | access::EXECUTABLE | access::READABLE, + granularity::GRANULARITY_4K | granularity::LONG_MODE + ); + + // User data segment (64-bit) + GDT[4].set_segment( + 0x00000000, + 0xFFFFF, + access::PRESENT | access::RING_3 | access::SYSTEM | access::WRITABLE, + granularity::GRANULARITY_4K | granularity::LONG_MODE + ); + + let gdt_ptr = GdtPointer { + limit: (size_of::<[GdtEntry; GDT_ENTRIES]>() - 1) as u16, + base: GDT.as_ptr() as u64, + }; + + // Load GDT + core::arch::asm!( + "lgdt [{}]", + in(reg) &gdt_ptr, + options(nostack, preserves_flags) + ); + + // Reload segment registers + core::arch::asm!( + "mov ax, 0x10", // Kernel data segment + "mov ds, ax", + "mov es, ax", + "mov fs, ax", + "mov gs, ax", + "mov ss, ax", + out("ax") _, + options(nostack, preserves_flags) + ); + + // Far jump to reload CS + core::arch::asm!( + "push 0x08", // Kernel code segment + "lea rax, [rip + 2f]", + "push rax", + "retfq", + "2:", + out("rax") _, + options(nostack, preserves_flags) + ); + } +} diff --git a/kernel/src/arch/x86_64/idt.rs b/kernel/src/arch/x86_64/idt.rs index b537b54..f5f415c 100644 --- a/kernel/src/arch/x86_64/idt.rs +++ b/kernel/src/arch/x86_64/idt.rs @@ -1,4 +1,492 @@ // SPDX-License-Identifier: GPL-2.0 -//! IDT stub -pub fn init() {} +//! Interrupt Descriptor Table (IDT) for x86_64 + +use core::mem::size_of; + +/// IDT Entry structure for x86_64 +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct IdtEntry { + pub offset_low: u16, // Handler function address bits 0-15 + pub selector: u16, // Code segment selector + pub ist: u8, // Interrupt stack table offset + pub type_attr: u8, // Type and attributes + pub offset_middle: u16, // Handler function address bits 16-31 + pub offset_high: u32, // Handler function address bits 32-63 + pub zero: u32, // Reserved, must be zero +} + +impl IdtEntry { + pub const fn new() -> Self { + Self { + offset_low: 0, + selector: 0, + ist: 0, + type_attr: 0, + offset_middle: 0, + offset_high: 0, + zero: 0, + } + } + + pub fn set_handler(&mut self, handler: extern "C" fn(), selector: u16, type_attr: u8) { + let addr = handler as u64; + + self.offset_low = (addr & 0xFFFF) as u16; + self.offset_middle = ((addr >> 16) & 0xFFFF) as u16; + self.offset_high = ((addr >> 32) & 0xFFFFFFFF) as u32; + + self.selector = selector; + self.type_attr = type_attr; + self.ist = 0; + self.zero = 0; + } +} + +/// IDT Pointer structure +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct IdtPointer { + pub limit: u16, + pub base: u64, +} + +/// IDT constants +pub const IDT_ENTRIES: usize = 256; + +/// IDT type and attribute flags +pub mod type_attr { + pub const PRESENT: u8 = 1 << 7; + pub const RING_0: u8 = 0 << 5; + pub const RING_1: u8 = 1 << 5; + pub const RING_2: u8 = 2 << 5; + pub const RING_3: u8 = 3 << 5; + pub const INTERRUPT_GATE: u8 = 0x0E; + pub const TRAP_GATE: u8 = 0x0F; + pub const TASK_GATE: u8 = 0x05; +} + +/// Global IDT +static mut IDT: [IdtEntry; IDT_ENTRIES] = [IdtEntry::new(); IDT_ENTRIES]; + +/// Exception handler stubs implemented in Rust +#[no_mangle] +pub extern "C" fn divide_error_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 0, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_divide_error(&ctx); +} + +#[no_mangle] +pub extern "C" fn debug_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 1, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_debug(&ctx); +} + +#[no_mangle] +pub extern "C" fn nmi_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 2, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_nmi(&ctx); +} + +#[no_mangle] +pub extern "C" fn breakpoint_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 3, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_breakpoint(&ctx); +} + +#[no_mangle] +pub extern "C" fn overflow_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 4, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_overflow(&ctx); +} + +#[no_mangle] +pub extern "C" fn bound_range_exceeded_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 5, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_bound_range_exceeded(&ctx); +} + +#[no_mangle] +pub extern "C" fn invalid_opcode_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 6, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_invalid_opcode(&ctx); +} + +#[no_mangle] +pub extern "C" fn device_not_available_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 7, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_device_not_available(&ctx); +} + +#[no_mangle] +pub extern "C" fn double_fault_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 8, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_double_fault(&ctx); +} + +#[no_mangle] +pub extern "C" fn invalid_tss_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 10, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_invalid_tss(&ctx); +} + +#[no_mangle] +pub extern "C" fn segment_not_present_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 11, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_segment_not_present(&ctx); +} + +#[no_mangle] +pub extern "C" fn stack_segment_fault_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 12, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_stack_segment_fault(&ctx); +} + +#[no_mangle] +pub extern "C" fn general_protection_fault_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 13, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_general_protection_fault(&ctx); +} + +#[no_mangle] +pub extern "C" fn page_fault_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 14, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_page_fault(&ctx); +} + +#[no_mangle] +pub extern "C" fn x87_fpu_error_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 16, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_x87_fpu_error(&ctx); +} + +#[no_mangle] +pub extern "C" fn alignment_check_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 17, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_alignment_check(&ctx); +} + +#[no_mangle] +pub extern "C" fn machine_check_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 18, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_machine_check(&ctx); +} + +#[no_mangle] +pub extern "C" fn simd_exception_handler() { + let ctx = ExceptionContext { + gs: 0, fs: 0, es: 0, ds: 0, + r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0, + rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0, + vector: 19, error_code: 0, + rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0, + }; + handle_simd_exception(&ctx); +} + +/// Initialize IDT +pub fn init() { + unsafe { + // Set up exception handlers + IDT[0].set_handler(divide_error_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[1].set_handler(debug_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[2].set_handler(nmi_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[3].set_handler(breakpoint_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE | type_attr::RING_3); + IDT[4].set_handler(overflow_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[5].set_handler(bound_range_exceeded_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[6].set_handler(invalid_opcode_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[7].set_handler(device_not_available_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[8].set_handler(double_fault_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[10].set_handler(invalid_tss_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[11].set_handler(segment_not_present_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[12].set_handler(stack_segment_fault_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[13].set_handler(general_protection_fault_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[14].set_handler(page_fault_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[16].set_handler(x87_fpu_error_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[17].set_handler(alignment_check_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[18].set_handler(machine_check_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + IDT[19].set_handler(simd_exception_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE); + + let idt_ptr = IdtPointer { + limit: (size_of::<[IdtEntry; IDT_ENTRIES]>() - 1) as u16, + base: IDT.as_ptr() as u64, + }; + + // Load IDT + core::arch::asm!( + "lidt [{}]", + in(reg) &idt_ptr, + options(nostack, preserves_flags) + ); + } +} + +/// Exception context structure passed from assembly +#[derive(Debug)] +#[repr(C)] +pub struct ExceptionContext { + // Segment registers + pub gs: u64, + pub fs: u64, + pub es: u64, + pub ds: u64, + + // General purpose registers + pub r15: u64, + pub r14: u64, + pub r13: u64, + pub r12: u64, + pub r11: u64, + pub r10: u64, + pub r9: u64, + pub r8: u64, + pub rdi: u64, + pub rsi: u64, + pub rbp: u64, + pub rbx: u64, + pub rdx: u64, + pub rcx: u64, + pub rax: u64, + + // Exception information + pub vector: u64, + pub error_code: u64, + + // Interrupt stack frame + pub rip: u64, + pub cs: u64, + pub eflags: u64, + pub rsp: u64, + pub ss: u64, +} + +/// Exception handler called from assembly +#[no_mangle] +pub extern "C" fn exception_handler(context: *const ExceptionContext) { + let ctx = unsafe { &*context }; + + match ctx.vector { + 0 => handle_divide_error(ctx), + 1 => handle_debug(ctx), + 2 => handle_nmi(ctx), + 3 => handle_breakpoint(ctx), + 4 => handle_overflow(ctx), + 5 => handle_bound_range_exceeded(ctx), + 6 => handle_invalid_opcode(ctx), + 7 => handle_device_not_available(ctx), + 8 => handle_double_fault(ctx), + 10 => handle_invalid_tss(ctx), + 11 => handle_segment_not_present(ctx), + 12 => handle_stack_segment_fault(ctx), + 13 => handle_general_protection_fault(ctx), + 14 => handle_page_fault(ctx), + 16 => handle_x87_fpu_error(ctx), + 17 => handle_alignment_check(ctx), + 18 => handle_machine_check(ctx), + 19 => handle_simd_exception(ctx), + _ => handle_unknown_exception(ctx), + } +} + +// Individual exception handlers +fn handle_divide_error(ctx: &ExceptionContext) { + crate::error!("Divide by zero error at RIP: 0x{:x}", ctx.rip); + panic!("Divide by zero exception"); +} + +fn handle_debug(ctx: &ExceptionContext) { + crate::info!("Debug exception at RIP: 0x{:x}", ctx.rip); +} + +fn handle_nmi(ctx: &ExceptionContext) { + crate::error!("Non-maskable interrupt at RIP: 0x{:x}", ctx.rip); +} + +fn handle_breakpoint(ctx: &ExceptionContext) { + crate::info!("Breakpoint at RIP: 0x{:x}", ctx.rip); +} + +fn handle_overflow(ctx: &ExceptionContext) { + crate::error!("Overflow exception at RIP: 0x{:x}", ctx.rip); + panic!("Overflow exception"); +} + +fn handle_bound_range_exceeded(ctx: &ExceptionContext) { + crate::error!("Bound range exceeded at RIP: 0x{:x}", ctx.rip); + panic!("Bound range exceeded"); +} + +fn handle_invalid_opcode(ctx: &ExceptionContext) { + crate::error!("Invalid opcode at RIP: 0x{:x}", ctx.rip); + panic!("Invalid opcode"); +} + +fn handle_device_not_available(ctx: &ExceptionContext) { + crate::error!("Device not available at RIP: 0x{:x}", ctx.rip); + panic!("Device not available"); +} + +fn handle_double_fault(ctx: &ExceptionContext) { + crate::error!("Double fault at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code); + panic!("Double fault"); +} + +fn handle_invalid_tss(ctx: &ExceptionContext) { + crate::error!("Invalid TSS at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code); + panic!("Invalid TSS"); +} + +fn handle_segment_not_present(ctx: &ExceptionContext) { + crate::error!("Segment not present at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code); + panic!("Segment not present"); +} + +fn handle_stack_segment_fault(ctx: &ExceptionContext) { + crate::error!("Stack segment fault at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code); + panic!("Stack segment fault"); +} + +fn handle_general_protection_fault(ctx: &ExceptionContext) { + crate::error!("General protection fault at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code); + panic!("General protection fault"); +} + +fn handle_page_fault(ctx: &ExceptionContext) { + // Get the faulting address from CR2 + let fault_addr: u64; + unsafe { + core::arch::asm!("mov {}, cr2", out(reg) fault_addr); + } + + crate::error!("Page fault at RIP: 0x{:x}, fault address: 0x{:x}, error code: 0x{:x}", + ctx.rip, fault_addr, ctx.error_code); + panic!("Page fault"); +} + +fn handle_x87_fpu_error(ctx: &ExceptionContext) { + crate::error!("x87 FPU error at RIP: 0x{:x}", ctx.rip); + panic!("x87 FPU error"); +} + +fn handle_alignment_check(ctx: &ExceptionContext) { + crate::error!("Alignment check at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code); + panic!("Alignment check"); +} + +fn handle_machine_check(ctx: &ExceptionContext) { + crate::error!("Machine check at RIP: 0x{:x}", ctx.rip); + panic!("Machine check"); +} + +fn handle_simd_exception(ctx: &ExceptionContext) { + crate::error!("SIMD exception at RIP: 0x{:x}", ctx.rip); + panic!("SIMD exception"); +} + +fn handle_unknown_exception(ctx: &ExceptionContext) { + crate::error!("Unknown exception {} at RIP: 0x{:x}", ctx.vector, ctx.rip); + panic!("Unknown exception"); +} diff --git a/kernel/src/arch/x86_64/port.rs b/kernel/src/arch/x86_64/port.rs index e65bbea..1add93e 100644 --- a/kernel/src/arch/x86_64/port.rs +++ b/kernel/src/arch/x86_64/port.rs @@ -30,3 +30,25 @@ impl Port { value } } + +/// Read a byte from a port +pub unsafe fn inb(port: u16) -> u8 { + let value: u8; + core::arch::asm!( + "in al, dx", + out("al") value, + in("dx") port, + options(nomem, nostack, preserves_flags) + ); + value +} + +/// Write a byte to a port +pub unsafe fn outb(port: u16, value: u8) { + core::arch::asm!( + "out dx, al", + in("dx") port, + in("al") value, + options(nomem, nostack, preserves_flags) + ); +} diff --git a/kernel/src/benchmark.rs b/kernel/src/benchmark.rs new file mode 100644 index 0000000..afc059f --- /dev/null +++ b/kernel/src/benchmark.rs @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Kernel benchmark system + +use crate::error::Result; +use crate::{info, warn}; +use crate::time::{get_jiffies, monotonic_time, TimeSpec}; +use alloc::{vec, vec::Vec, string::{String, ToString}}; + +/// Benchmark result +#[derive(Debug, Clone)] +pub struct BenchmarkResult { + pub name: String, + pub iterations: u64, + pub total_time_ns: u64, + pub avg_time_ns: u64, + pub min_time_ns: u64, + pub max_time_ns: u64, +} + +impl BenchmarkResult { + pub fn new(name: String, iterations: u64, times: &[u64]) -> Self { + let total_time_ns = times.iter().sum(); + let avg_time_ns = total_time_ns / iterations; + let min_time_ns = *times.iter().min().unwrap_or(&0); + let max_time_ns = *times.iter().max().unwrap_or(&0); + + Self { + name, + iterations, + total_time_ns, + avg_time_ns, + min_time_ns, + max_time_ns, + } + } + + pub fn print(&self) { + info!("Benchmark: {}", self.name); + info!(" Iterations: {}", self.iterations); + info!(" Total time: {} ns", self.total_time_ns); + info!(" Average time: {} ns", self.avg_time_ns); + info!(" Min time: {} ns", self.min_time_ns); + info!(" Max time: {} ns", self.max_time_ns); + } +} + +/// Benchmark function type +pub type BenchmarkFn = fn(); + +/// Run a benchmark +pub fn benchmark(name: &str, iterations: u64, func: BenchmarkFn) -> BenchmarkResult { + let mut times = Vec::new(); + + info!("Running benchmark: {} ({} iterations)", name, iterations); + + for _i in 0..iterations { + let start = monotonic_time(); + func(); + let end = monotonic_time(); + + let elapsed_ns = (end.to_ns() as i64 - start.to_ns() as i64) as u64; + times.push(elapsed_ns); + } + + let result = BenchmarkResult::new(name.to_string(), iterations, ×); + result.print(); + result +} + +/// Memory allocation benchmark +fn bench_memory_alloc() { + let _vec: Vec = Vec::with_capacity(1024); +} + +/// Memory deallocation benchmark +fn bench_memory_dealloc() { + let vec: Vec = Vec::with_capacity(1024); + drop(vec); +} + +/// Simple arithmetic benchmark +fn bench_arithmetic() { + let mut result = 0u64; + for i in 0..1000 { + result = result.wrapping_add(i).wrapping_mul(2); + } + // Prevent optimization + core::hint::black_box(result); +} + +/// String operations benchmark +fn bench_string_ops() { + let mut s = String::new(); + for i in 0..100 { + s.push_str("test"); + s.push((b'0' + (i % 10) as u8) as char); + } + core::hint::black_box(s); +} + +/// Interrupt enable/disable benchmark +fn bench_interrupt_toggle() { + crate::interrupt::disable(); + crate::interrupt::enable(); +} + +/// Run all kernel benchmarks +pub fn run_all_benchmarks() -> Result> { + info!("Running kernel performance benchmarks"); + + let mut results = Vec::new(); + + // Memory benchmarks + results.push(benchmark("memory_alloc", 1000, bench_memory_alloc)); + results.push(benchmark("memory_dealloc", 1000, bench_memory_dealloc)); + + // CPU benchmarks + results.push(benchmark("arithmetic", 100, bench_arithmetic)); + results.push(benchmark("string_ops", 100, bench_string_ops)); + + // System call benchmarks + results.push(benchmark("interrupt_toggle", 1000, bench_interrupt_toggle)); + + info!("Benchmark suite completed"); + Ok(results) +} + +/// Run specific benchmark +pub fn run_benchmark(name: &str, iterations: u64) -> Result { + match name { + "memory_alloc" => Ok(benchmark(name, iterations, bench_memory_alloc)), + "memory_dealloc" => Ok(benchmark(name, iterations, bench_memory_dealloc)), + "arithmetic" => Ok(benchmark(name, iterations, bench_arithmetic)), + "string_ops" => Ok(benchmark(name, iterations, bench_string_ops)), + "interrupt_toggle" => Ok(benchmark(name, iterations, bench_interrupt_toggle)), + _ => { + warn!("Unknown benchmark: {}", name); + Err(crate::error::Error::NotFound) + } + } +} + +/// Get available benchmarks +pub fn list_benchmarks() -> Vec<&'static str> { + vec![ + "memory_alloc", + "memory_dealloc", + "arithmetic", + "string_ops", + "interrupt_toggle", + ] +} + +/// Performance stress test +pub fn stress_test(duration_seconds: u64) -> Result<()> { + info!("Running stress test for {} seconds", duration_seconds); + + let start_jiffies = get_jiffies(); + let target_jiffies = start_jiffies.0 + (duration_seconds * crate::time::HZ); + + let mut iterations = 0u64; + + while get_jiffies().0 < target_jiffies { + // Mix of different operations + bench_arithmetic(); + bench_memory_alloc(); + bench_string_ops(); + bench_interrupt_toggle(); + + iterations += 1; + + // Yield occasionally to prevent monopolizing CPU + if iterations % 1000 == 0 { + crate::kthread::kthread_yield(); + } + } + + let elapsed_jiffies = get_jiffies().0 - start_jiffies.0; + let ops_per_second = (iterations * crate::time::HZ) / elapsed_jiffies; + + info!("Stress test completed:"); + info!(" Duration: {} jiffies", elapsed_jiffies); + info!(" Total iterations: {}", iterations); + info!(" Operations per second: {}", ops_per_second); + + Ok(()) +} diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index 3d93940..cd4c03f 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -29,6 +29,7 @@ pub struct BootInfo { pub command_line: Option, pub initrd_start: Option, pub initrd_size: Option, + pub multiboot_addr: Option, } impl BootInfo { @@ -41,6 +42,7 @@ impl BootInfo { command_line: None, initrd_start: None, initrd_size: None, + multiboot_addr: None, } } } @@ -54,10 +56,14 @@ pub static mut BOOT_INFO: BootInfo = BootInfo { command_line: None, initrd_start: None, initrd_size: None, + multiboot_addr: None, }; -pub fn init() -> Result<()> { - complete_boot() +/// Set multiboot information address +pub fn set_multiboot_info(addr: usize) { + unsafe { + BOOT_INFO.multiboot_addr = Some(addr); + } } /// Get boot information @@ -65,177 +71,173 @@ pub fn get_boot_info() -> &'static BootInfo { unsafe { &BOOT_INFO } } +/// Update boot information +pub unsafe fn update_boot_info(f: F) where F: FnOnce(&mut BootInfo) { + f(&mut BOOT_INFO); +} + +pub mod multiboot { + use crate::types::{PhysAddr, VirtAddr}; + use crate::error::Result; + use crate::info; + + /// Multiboot2 information structure + #[repr(C)] + pub struct MultibootInfo { + pub total_size: u32, + pub reserved: u32, + } + + /// Memory map entry from multiboot + #[repr(C)] + #[derive(Debug, Clone, Copy)] + pub struct MemoryMapEntry { + pub base_addr: u64, + pub length: u64, + pub type_: u32, + pub reserved: u32, + } + + /// Memory map types + pub mod memory_type { + pub const AVAILABLE: u32 = 1; + pub const RESERVED: u32 = 2; + pub const ACPI_RECLAIMABLE: u32 = 3; + pub const NVS: u32 = 4; + pub const BADRAM: u32 = 5; + } + + /// Boot memory information + #[derive(Debug)] + pub struct BootMemoryInfo { + pub total_memory: u64, + pub available_memory: u64, + pub memory_regions: alloc::vec::Vec, + } + + impl BootMemoryInfo { + pub fn new() -> Self { + Self { + total_memory: 0, + available_memory: 0, + memory_regions: alloc::vec::Vec::new(), + } + } + + pub fn add_region(&mut self, entry: MemoryMapEntry) { + if entry.type_ == memory_type::AVAILABLE { + self.available_memory += entry.length; + } + self.total_memory += entry.length; + self.memory_regions.push(entry); + } + } + + /// Parse multiboot2 information and initialize memory management + pub fn init_memory_from_multiboot(multiboot_addr: usize) -> Result<()> { + info!("Parsing multiboot information at 0x{:x}", multiboot_addr); + + let multiboot_info = unsafe { &*(multiboot_addr as *const MultibootInfo) }; + + info!("Multiboot info size: {} bytes", multiboot_info.total_size); + + // Parse memory map from multiboot info + let mut memory_info = BootMemoryInfo::new(); + + // For now, assume a basic memory layout if we can't parse multiboot properly + // This is a fallback to make the kernel bootable + let default_memory = MemoryMapEntry { + base_addr: 0x100000, // 1MB + length: 0x7F00000, // ~127MB (assuming 128MB total RAM) + type_: memory_type::AVAILABLE, + reserved: 0, + }; + + memory_info.add_region(default_memory); + + // Update global boot info + unsafe { + super::update_boot_info(|boot_info| { + boot_info.memory_size = memory_info.total_memory as usize; + boot_info.available_memory = memory_info.available_memory as usize; + }); + } + + // Initialize page allocator with available memory + for region in &memory_info.memory_regions { + if region.type_ == memory_type::AVAILABLE { + let start_pfn = region.base_addr / 4096; + let end_pfn = (region.base_addr + region.length) / 4096; + + info!("Adding memory region: 0x{:x}-0x{:x}", + region.base_addr, region.base_addr + region.length); + + // Add this memory region to the page allocator + crate::memory::page::add_free_range( + PhysAddr::new(region.base_addr as usize), + PhysAddr::new((region.base_addr + region.length) as usize) + )?; + } + } + + info!("Memory initialization from multiboot completed"); + info!("Total memory: {} bytes", memory_info.total_memory); + info!("Available memory: {} bytes", memory_info.available_memory); + + Ok(()) + } +} + +/// Early boot setup before memory allocation is available +pub fn early_boot_setup() -> Result<()> { + info!("Early boot setup"); + + // Basic hardware initialization + // This is done before memory allocators are available + + Ok(()) +} + +/// Boot stage management +static mut CURRENT_BOOT_STAGE: BootStage = BootStage::EarlyInit; + +/// Get current boot stage +pub fn get_boot_stage() -> BootStage { + unsafe { CURRENT_BOOT_STAGE } +} + +/// Set boot stage +pub fn set_boot_stage(stage: BootStage) { + unsafe { + CURRENT_BOOT_STAGE = stage; + } + info!("Boot stage: {:?}", stage); +} + /// Complete boot process pub fn complete_boot() -> Result<()> { - info!("=== Rust Kernel Boot Process ==="); - - // Stage 1: Early initialization - info!("Stage 1: Early initialization"); - early_hardware_init()?; - - // Stage 2: Memory management - info!("Stage 2: Memory management initialization"); - crate::memory::init()?; - crate::memory::kmalloc::init()?; - crate::memory::vmalloc::init()?; - - // Stage 3: Interrupt handling - info!("Stage 3: Interrupt handling initialization"); - crate::interrupt::init()?; - - // Stage 4: Device management - info!("Stage 4: Device management initialization"); - crate::device::init()?; - crate::device_advanced::init_advanced()?; - - // Stage 5: Process and scheduler - info!("Stage 5: Process and scheduler initialization"); - crate::process::init()?; - crate::scheduler::init()?; - - // Stage 6: File system - info!("Stage 6: File system initialization"); - crate::fs::init()?; - - // Stage 7: Network stack - info!("Stage 7: Network stack initialization"); - crate::network::init()?; - - // Stage 8: Load initial ramdisk - if let Some(initrd_start) = unsafe { BOOT_INFO.initrd_start } { - info!("Stage 8: Loading initial ramdisk from 0x{:x}", initrd_start); - load_initrd(initrd_start, unsafe { BOOT_INFO.initrd_size.unwrap_or(0) })?; - } else { - info!("Stage 8: No initial ramdisk found"); - } - - // Stage 9: Start init process - info!("Stage 9: Starting init process"); - start_init_process()?; - - info!("=== Boot Complete ==="); - info!("Kernel version: {} v{}", crate::NAME, crate::VERSION); - info!("Total memory: {} MB", unsafe { BOOT_INFO.memory_size } / 1024 / 1024); - info!("Available memory: {} MB", unsafe { BOOT_INFO.available_memory } / 1024 / 1024); - info!("CPU count: {}", unsafe { BOOT_INFO.cpu_count }); - + set_boot_stage(BootStage::Complete); + info!("Boot process completed successfully"); Ok(()) } -/// Early hardware initialization -fn early_hardware_init() -> Result<()> { - info!("Initializing early hardware..."); - - // Initialize console first - crate::console::init()?; - - // Detect CPU features - detect_cpu_features()?; - - // Initialize architecture-specific features - #[cfg(target_arch = "x86_64")] - init_x86_64_features()?; - - // Detect memory layout - detect_memory_layout()?; - - info!("Early hardware initialization complete"); - Ok(()) -} - -/// Detect CPU features -fn detect_cpu_features() -> Result<()> { - info!("Detecting CPU features..."); - - #[cfg(target_arch = "x86_64")] - { - // TODO: Implement CPUID detection without register conflicts - // For now, just log that we're skipping detailed CPU detection - info!("CPU Vendor: Unknown (CPUID detection disabled)"); - info!("CPU Features: Basic x86_64 assumed"); - } - - Ok(()) -} - -/// Initialize x86_64-specific features -#[cfg(target_arch = "x86_64")] -fn init_x86_64_features() -> Result<()> { - info!("Initializing x86_64 features..."); - - // Initialize GDT (Global Descriptor Table) - // TODO: Set up proper GDT with kernel/user segments - - // Enable important CPU features +/// Initialize multiboot information +/// This should be called at the very beginning of kernel execution +pub fn multiboot_init() { + // TODO: Parse multiboot information from bootloader + // For now, initialize with default values unsafe { - // Enable SSE/SSE2 if available - let mut cr0: u64; - core::arch::asm!("mov {}, cr0", out(reg) cr0); - cr0 &= !(1 << 2); // Clear EM (emulation) bit - cr0 |= 1 << 1; // Set MP (monitor coprocessor) bit - core::arch::asm!("mov cr0, {}", in(reg) cr0); - - let mut cr4: u64; - core::arch::asm!("mov {}, cr4", out(reg) cr4); - cr4 |= 1 << 9; // Set OSFXSR (OS supports FXSAVE/FXRSTOR) - cr4 |= 1 << 10; // Set OSXMMEXCPT (OS supports unmasked SIMD FP exceptions) - core::arch::asm!("mov cr4, {}", in(reg) cr4); + BOOT_INFO = BootInfo { + memory_size: 512 * 1024 * 1024, // 512MB default + available_memory: 480 * 1024 * 1024, // 480MB available + cpu_count: 1, + boot_time: 0, + command_line: None, + initrd_start: None, + initrd_size: None, + multiboot_addr: None, + }; } - info!("x86_64 features initialized"); - Ok(()) -} - -/// Detect memory layout -fn detect_memory_layout() -> Result<()> { - info!("Detecting memory layout..."); - - // For now, use conservative defaults - // In a real implementation, this would parse multiboot info or UEFI memory map - unsafe { - BOOT_INFO.memory_size = 128 * 1024 * 1024; // 128 MB default - BOOT_INFO.available_memory = 64 * 1024 * 1024; // 64 MB available - BOOT_INFO.cpu_count = 1; - } - - info!("Memory layout detected: {} MB total, {} MB available", - unsafe { BOOT_INFO.memory_size } / 1024 / 1024, - unsafe { BOOT_INFO.available_memory } / 1024 / 1024); - - Ok(()) -} - -/// Load initial ramdisk -fn load_initrd(_start: usize, _size: usize) -> Result<()> { - info!("Loading initial ramdisk..."); - - // TODO: Parse and mount initrd as root filesystem - // This would involve: - // 1. Validating the initrd format (cpio, tar, etc.) - // 2. Creating a ramdisk device - // 3. Mounting it as the root filesystem - // 4. Extracting files to the ramdisk - - info!("Initial ramdisk loaded"); - Ok(()) -} - -/// Start init process -fn start_init_process() -> Result<()> { - info!("Starting init process..."); - - // Create init process (PID 1) - let init_pid = crate::process::create_process( - "/sbin/init".to_string(), - crate::types::Uid(0), // root - crate::types::Gid(0), // root - )?; - - info!("Init process started with PID {}", init_pid.0); - - // TODO: Load init binary from filesystem - // TODO: Set up initial environment - // TODO: Start init process execution - - Ok(()) + info!("Multiboot information initialized"); } diff --git a/kernel/src/boot_clean.rs b/kernel/src/boot_clean.rs new file mode 100644 index 0000000..0ac44b3 --- /dev/null +++ b/kernel/src/boot_clean.rs @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Boot process and hardware initialization + +use crate::{info, error}; +use crate::error::Result; +use alloc::string::ToString; + +/// Boot stages +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BootStage { + EarlyInit, + MemoryInit, + DeviceInit, + SchedulerInit, + FileSystemInit, + NetworkInit, + UserSpaceInit, + Complete, +} + +/// Boot information structure +#[derive(Debug)] +pub struct BootInfo { + pub memory_size: usize, + pub available_memory: usize, + pub cpu_count: usize, + pub boot_time: u64, + pub command_line: Option, + pub initrd_start: Option, + pub initrd_size: Option, + pub multiboot_addr: Option, +} + +impl BootInfo { + pub fn new() -> Self { + Self { + memory_size: 0, + available_memory: 0, + cpu_count: 1, + boot_time: 0, + command_line: None, + initrd_start: None, + initrd_size: None, + multiboot_addr: None, + } + } +} + +/// Global boot information +pub static mut BOOT_INFO: BootInfo = BootInfo { + memory_size: 0, + available_memory: 0, + cpu_count: 1, + boot_time: 0, + command_line: None, + initrd_start: None, + initrd_size: None, + multiboot_addr: None, +}; + +/// Set multiboot information address +pub fn set_multiboot_info(addr: usize) { + unsafe { + BOOT_INFO.multiboot_addr = Some(addr); + } +} + +/// Get boot information +pub fn get_boot_info() -> &'static BootInfo { + unsafe { &BOOT_INFO } +} + +/// Update boot information +pub unsafe fn update_boot_info(f: F) where F: FnOnce(&mut BootInfo) { + f(&mut BOOT_INFO); +} + +pub mod multiboot { + use crate::types::{PhysAddr, VirtAddr}; + use crate::error::Result; + + /// Multiboot2 information structure + #[repr(C)] + pub struct MultibootInfo { + pub total_size: u32, + pub reserved: u32, + } + + /// Memory map entry from multiboot + #[repr(C)] + #[derive(Debug, Clone, Copy)] + pub struct MemoryMapEntry { + pub base_addr: u64, + pub length: u64, + pub type_: u32, + pub reserved: u32, + } + + /// Memory map types + pub mod memory_type { + pub const AVAILABLE: u32 = 1; + pub const RESERVED: u32 = 2; + pub const ACPI_RECLAIMABLE: u32 = 3; + pub const NVS: u32 = 4; + pub const BADRAM: u32 = 5; + } + + /// Boot memory information + #[derive(Debug)] + pub struct BootMemoryInfo { + pub total_memory: u64, + pub available_memory: u64, + pub memory_regions: alloc::vec::Vec, + } + + impl BootMemoryInfo { + pub fn new() -> Self { + Self { + total_memory: 0, + available_memory: 0, + memory_regions: alloc::vec::Vec::new(), + } + } + + pub fn add_region(&mut self, entry: MemoryMapEntry) { + if entry.type_ == memory_type::AVAILABLE { + self.available_memory += entry.length; + } + self.total_memory += entry.length; + self.memory_regions.push(entry); + } + } + + /// Parse multiboot2 information and initialize memory management + pub fn init_memory_from_multiboot(multiboot_addr: usize) -> Result<()> { + info!("Parsing multiboot information at 0x{:x}", multiboot_addr); + + let multiboot_info = unsafe { &*(multiboot_addr as *const MultibootInfo) }; + + info!("Multiboot info size: {} bytes", multiboot_info.total_size); + + // Parse memory map from multiboot info + let mut memory_info = BootMemoryInfo::new(); + + // For now, assume a basic memory layout if we can't parse multiboot properly + // This is a fallback to make the kernel bootable + let default_memory = MemoryMapEntry { + base_addr: 0x100000, // 1MB + length: 0x7F00000, // ~127MB (assuming 128MB total RAM) + type_: memory_type::AVAILABLE, + reserved: 0, + }; + + memory_info.add_region(default_memory); + + // Update global boot info + unsafe { + super::update_boot_info(|boot_info| { + boot_info.memory_size = memory_info.total_memory as usize; + boot_info.available_memory = memory_info.available_memory as usize; + }); + } + + // Initialize page allocator with available memory + for region in &memory_info.memory_regions { + if region.type_ == memory_type::AVAILABLE { + let start_pfn = region.base_addr / 4096; + let end_pfn = (region.base_addr + region.length) / 4096; + + info!("Adding memory region: 0x{:x}-0x{:x}", + region.base_addr, region.base_addr + region.length); + + // Add this memory region to the page allocator + crate::memory::page::add_free_range( + PhysAddr::new(region.base_addr as usize), + PhysAddr::new((region.base_addr + region.length) as usize) + )?; + } + } + + info!("Memory initialization from multiboot completed"); + info!("Total memory: {} bytes", memory_info.total_memory); + info!("Available memory: {} bytes", memory_info.available_memory); + + Ok(()) + } +} + +/// Early boot setup before memory allocation is available +pub fn early_boot_setup() -> Result<()> { + info!("Early boot setup"); + + // Basic hardware initialization + // This is done before memory allocators are available + + Ok(()) +} + +/// Boot stage management +static mut CURRENT_BOOT_STAGE: BootStage = BootStage::EarlyInit; + +/// Get current boot stage +pub fn get_boot_stage() -> BootStage { + unsafe { CURRENT_BOOT_STAGE } +} + +/// Set boot stage +pub fn set_boot_stage(stage: BootStage) { + unsafe { + CURRENT_BOOT_STAGE = stage; + } + info!("Boot stage: {:?}", stage); +} + +/// Complete boot process +pub fn complete_boot() -> Result<()> { + set_boot_stage(BootStage::Complete); + info!("Boot process completed successfully"); + Ok(()) +} diff --git a/kernel/src/console.rs b/kernel/src/console.rs index 2ca547a..3a879c6 100644 --- a/kernel/src/console.rs +++ b/kernel/src/console.rs @@ -122,7 +122,7 @@ impl Console { self.column_position = 0; } - fn write_str(&mut self, s: &str) { + pub fn write_str(&mut self, s: &str) { if !self.initialized { return; } @@ -241,6 +241,12 @@ pub fn print_info(message: &str) { writer.write_str(message).unwrap(); } +/// Write string to console +pub fn write_str(s: &str) { + let mut console = CONSOLE.lock(); + console.write_str(s); +} + struct ConsoleWriter<'a>(&'a mut Console); impl Write for ConsoleWriter<'_> { diff --git a/kernel/src/diagnostics.rs b/kernel/src/diagnostics.rs new file mode 100644 index 0000000..928028c --- /dev/null +++ b/kernel/src/diagnostics.rs @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Kernel diagnostics and health monitoring + +use crate::error::Result; +use crate::sync::Spinlock; +use crate::time::get_jiffies; +use crate::types::Jiffies; +use alloc::{vec::Vec, string::String, format}; +use core::fmt::Write; + +/// System health status +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum HealthStatus { + Healthy, + Warning, + Critical, + Unknown, +} + +/// Diagnostic category +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DiagnosticCategory { + Memory, + CPU, + IO, + Network, + FileSystem, + Process, + Kernel, +} + +/// Diagnostic entry +#[derive(Debug, Clone)] +pub struct DiagnosticEntry { + pub category: DiagnosticCategory, + pub status: HealthStatus, + pub message: String, + pub timestamp: Jiffies, + pub details: Option, +} + +/// System diagnostics +pub struct SystemDiagnostics { + entries: Vec, + last_check: Jiffies, + health_status: HealthStatus, +} + +static DIAGNOSTICS: Spinlock = Spinlock::new(SystemDiagnostics::new()); + +impl SystemDiagnostics { + const fn new() -> Self { + Self { + entries: Vec::new(), + last_check: Jiffies(0), + health_status: HealthStatus::Unknown, + } + } + + fn add_entry(&mut self, entry: DiagnosticEntry) { + // Keep only the last 1000 entries + if self.entries.len() >= 1000 { + self.entries.remove(0); + } + + // Update overall health status + match entry.status { + HealthStatus::Critical => self.health_status = HealthStatus::Critical, + HealthStatus::Warning if self.health_status != HealthStatus::Critical => { + self.health_status = HealthStatus::Warning; + } + HealthStatus::Healthy if self.health_status == HealthStatus::Unknown => { + self.health_status = HealthStatus::Healthy; + } + _ => {} + } + + self.entries.push(entry); + } + + fn get_entries_by_category(&self, category: DiagnosticCategory) -> Vec<&DiagnosticEntry> { + self.entries.iter() + .filter(|entry| entry.category == category) + .collect() + } + + fn get_recent_entries(&self, max_age_jiffies: u64) -> Vec<&DiagnosticEntry> { + let current_time = get_jiffies(); + self.entries.iter() + .filter(|entry| { + (current_time - entry.timestamp).as_u64() <= max_age_jiffies + }) + .collect() + } +} + +/// Initialize diagnostics system +pub fn init_diagnostics() -> Result<()> { + let mut diag = DIAGNOSTICS.lock(); + diag.last_check = get_jiffies(); + diag.health_status = HealthStatus::Healthy; + + // Add initial diagnostic entry + let entry = DiagnosticEntry { + category: DiagnosticCategory::Kernel, + status: HealthStatus::Healthy, + message: "Diagnostics system initialized".into(), + timestamp: get_jiffies(), + details: None, + }; + diag.add_entry(entry); + + Ok(()) +} + +/// Add a diagnostic entry +pub fn add_diagnostic( + category: DiagnosticCategory, + status: HealthStatus, + message: &str, + details: Option<&str>, +) { + let mut diag = DIAGNOSTICS.lock(); + let entry = DiagnosticEntry { + category, + status, + message: message.into(), + timestamp: get_jiffies(), + details: details.map(|s| s.into()), + }; + diag.add_entry(entry); +} + +/// Get system health status +pub fn get_health_status() -> HealthStatus { + let diag = DIAGNOSTICS.lock(); + diag.health_status +} + +/// Run system health check +pub fn run_health_check() -> Result<()> { + let mut issues_found = 0; + + // Check memory usage + if let Ok(stats) = crate::memory::get_memory_stats() { + if stats.usage_percent > 90 { + add_diagnostic( + DiagnosticCategory::Memory, + HealthStatus::Critical, + "High memory usage", + Some(&format!("Memory usage: {}%", stats.usage_percent)), + ); + issues_found += 1; + } else if stats.usage_percent > 75 { + add_diagnostic( + DiagnosticCategory::Memory, + HealthStatus::Warning, + "Elevated memory usage", + Some(&format!("Memory usage: {}%", stats.usage_percent)), + ); + } + } + + // Check kernel threads + if let Ok(thread_count) = crate::kthread::get_thread_count() { + if thread_count == 0 { + add_diagnostic( + DiagnosticCategory::Kernel, + HealthStatus::Warning, + "No kernel threads running", + None, + ); + } + } + + // Check file system + if let Ok(fs_stats) = crate::memfs::get_filesystem_stats() { + if fs_stats.files_count > 10000 { + add_diagnostic( + DiagnosticCategory::FileSystem, + HealthStatus::Warning, + "High number of files", + Some(&format!("Files: {}", fs_stats.files_count)), + ); + } + } + + // Update last check time + { + let mut diag = DIAGNOSTICS.lock(); + diag.last_check = get_jiffies(); + } + + if issues_found == 0 { + add_diagnostic( + DiagnosticCategory::Kernel, + HealthStatus::Healthy, + "Health check completed - system healthy", + None, + ); + } + + Ok(()) +} + +/// Get diagnostic report +pub fn get_diagnostic_report() -> String { + let diag = DIAGNOSTICS.lock(); + let mut report = String::new(); + + writeln!(&mut report, "=== System Diagnostics Report ===").unwrap(); + writeln!(&mut report, "Overall Health: {:?}", diag.health_status).unwrap(); + writeln!(&mut report, "Last Check: {}", diag.last_check.as_u64()).unwrap(); + writeln!(&mut report, "Total Entries: {}", diag.entries.len()).unwrap(); + writeln!(&mut report).unwrap(); + + // Group by category + for category in [ + DiagnosticCategory::Kernel, + DiagnosticCategory::Memory, + DiagnosticCategory::CPU, + DiagnosticCategory::IO, + DiagnosticCategory::Network, + DiagnosticCategory::FileSystem, + DiagnosticCategory::Process, + ] { + let entries = diag.get_entries_by_category(category); + if !entries.is_empty() { + writeln!(&mut report, "{:?} ({} entries):", category, entries.len()).unwrap(); + for entry in entries.iter().rev().take(5) { // Show last 5 entries + writeln!(&mut report, " [{:?}] {} ({})", + entry.status, entry.message, entry.timestamp.as_u64()).unwrap(); + if let Some(details) = &entry.details { + writeln!(&mut report, " Details: {}", details).unwrap(); + } + } + writeln!(&mut report).unwrap(); + } + } + + report +} + +/// Get recent critical issues +pub fn get_critical_issues() -> Vec { + let diag = DIAGNOSTICS.lock(); + diag.entries.iter() + .filter(|entry| entry.status == HealthStatus::Critical) + .rev() + .take(10) + .cloned() + .collect() +} + +/// Clear diagnostic history +pub fn clear_diagnostics() { + let mut diag = DIAGNOSTICS.lock(); + diag.entries.clear(); + diag.health_status = HealthStatus::Healthy; + + // Add cleared entry + let entry = DiagnosticEntry { + category: DiagnosticCategory::Kernel, + status: HealthStatus::Healthy, + message: "Diagnostic history cleared".into(), + timestamp: get_jiffies(), + details: None, + }; + diag.add_entry(entry); +} + +/// Automatic health monitoring task +pub fn health_monitor_task() { + loop { + // Run health check every 30 seconds (30000 jiffies at 1000 Hz) + if let Err(_) = run_health_check() { + add_diagnostic( + DiagnosticCategory::Kernel, + HealthStatus::Warning, + "Health check failed", + None, + ); + } + + // Sleep for 30 seconds + crate::kthread::sleep_for_jiffies(30000); + } +} diff --git a/kernel/src/drivers_init.rs b/kernel/src/drivers_init.rs new file mode 100644 index 0000000..8a51043 --- /dev/null +++ b/kernel/src/drivers_init.rs @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Driver initialization and management + +use crate::error::Result; +use crate::{info, warn}; + +/// Initialize all built-in drivers +pub fn init_drivers() -> Result<()> { + info!("Initializing built-in drivers"); + + // Initialize keyboard driver + init_keyboard_driver()?; + + // Initialize serial driver + init_serial_driver()?; + + // Initialize ramdisk driver + init_ramdisk_driver()?; + + info!("Built-in drivers initialized"); + Ok(()) +} + +/// Initialize PS/2 keyboard driver +fn init_keyboard_driver() -> Result<()> { + info!("Initializing PS/2 keyboard driver"); + + // Register keyboard interrupt handler (IRQ 1) + if let Err(e) = crate::interrupt::request_irq( + 1, + keyboard_interrupt_handler, + 0, + "keyboard", + core::ptr::null_mut(), + ) { + warn!("Failed to register keyboard interrupt: {}", e); + return Err(e); + } + + info!("PS/2 keyboard driver initialized"); + Ok(()) +} + +/// Initialize serial driver +fn init_serial_driver() -> Result<()> { + info!("Initializing serial driver"); + + // Register serial interrupt handlers (IRQ 3 and 4) + if let Err(e) = crate::interrupt::request_irq( + 3, + serial_interrupt_handler, + 0, + "serial", + core::ptr::null_mut(), + ) { + warn!("Failed to register serial interrupt: {}", e); + } + + if let Err(e) = crate::interrupt::request_irq( + 4, + serial_interrupt_handler, + 0, + "serial", + core::ptr::null_mut(), + ) { + warn!("Failed to register serial interrupt: {}", e); + } + + info!("Serial driver initialized"); + Ok(()) +} + +/// Initialize ramdisk driver +fn init_ramdisk_driver() -> Result<()> { + info!("Initializing ramdisk driver"); + + // TODO: Create ramdisk device + // This would typically involve: + // 1. Allocating memory for the ramdisk + // 2. Registering the device with the block device subsystem + // 3. Setting up device file operations + + info!("Ramdisk driver initialized"); + Ok(()) +} + +/// Keyboard interrupt handler +fn keyboard_interrupt_handler(irq: u32, dev_id: *mut u8) -> crate::interrupt::IrqReturn { + // Read the scan code from the keyboard controller + let scancode = unsafe { crate::arch::x86_64::port::inb(0x60) }; + + // Convert scan code to ASCII (simplified) + if scancode < 128 { + let ascii = SCANCODE_TO_ASCII[scancode as usize]; + if ascii != 0 { + // Send character to kernel shell + if let Err(e) = crate::shell::shell_input(ascii as char) { + crate::warn!("Failed to process shell input: {}", e); + } + } + } + + crate::interrupt::IrqReturn::Handled +} + +/// Serial interrupt handler +fn serial_interrupt_handler(irq: u32, dev_id: *mut u8) -> crate::interrupt::IrqReturn { + // TODO: Handle serial port interrupts + // This would typically involve reading from the serial port + // and handling incoming data + + crate::interrupt::IrqReturn::Handled +} + +/// Keyboard scan code to ASCII mapping (simplified US layout) +const SCANCODE_TO_ASCII: [u8; 128] = [ + 0, 27, b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'0', b'-', b'=', 8, // 0-14 + b'\t', b'q', b'w', b'e', b'r', b't', b'y', b'u', b'i', b'o', b'p', b'[', b']', b'\n', // 15-28 + 0, // 29 ctrl + b'a', b's', b'd', b'f', b'g', b'h', b'j', b'k', b'l', b';', b'\'', b'`', // 30-41 + 0, // 42 left shift + b'\\', b'z', b'x', b'c', b'v', b'b', b'n', b'm', b',', b'.', b'/', // 43-53 + 0, // 54 right shift + b'*', 0, // 55-56 alt + b' ', // 57 space + 0, // 58 caps lock + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 59-68 F1-F10 + 0, 0, // 69-70 num lock, scroll lock + b'7', b'8', b'9', b'-', b'4', b'5', b'6', b'+', b'1', b'2', b'3', b'0', b'.', // 71-83 numpad + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 84-99 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100-115 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 116-127 +]; diff --git a/kernel/src/init.rs b/kernel/src/init.rs index 7de8f77..30903fc 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -92,8 +92,97 @@ pub fn main_init() -> ! { } info!("Time management initialized"); - // TODO: Initialize drivers - // init_drivers(); + // Display system information + crate::test_init::display_system_info(); + + // Run basic functionality tests + if let Err(e) = crate::test_init::run_basic_tests() { + error!("Basic functionality tests failed: {}", e); + panic!("Basic tests failed"); + } + + // Run initialization tests + if let Err(e) = crate::test_init::run_init_tests() { + error!("Initialization tests failed: {}", e); + panic!("Initialization tests failed"); + } + + // Initialize drivers + if let Err(e) = crate::drivers_init::init_drivers() { + error!("Failed to initialize drivers: {}", e); + panic!("Driver initialization failed"); + } + info!("Drivers initialized"); + + // Initialize kernel threads + if let Err(e) = crate::kthread::init_kthreads() { + error!("Failed to initialize kernel threads: {}", e); + panic!("Kernel thread initialization failed"); + } + info!("Kernel threads initialized"); + + // Initialize kernel shell + if let Err(e) = crate::shell::init_shell() { + error!("Failed to initialize kernel shell: {}", e); + panic!("Shell initialization failed"); + } + info!("Kernel shell initialized"); + + // Initialize basic networking + if let Err(e) = crate::net_basic::init_networking() { + error!("Failed to initialize networking: {}", e); + panic!("Networking initialization failed"); + } + info!("Basic networking initialized"); + + // Initialize module loading system + if let Err(e) = crate::module_loader::init_modules() { + error!("Failed to initialize module system: {}", e); + panic!("Module system initialization failed"); + } + info!("Module system initialized"); + + // Initialize in-memory file system + if let Err(e) = crate::memfs::init_memfs() { + error!("Failed to initialize file system: {}", e); + panic!("File system initialization failed"); + } + info!("In-memory file system initialized"); + + // Initialize user mode support + if let Err(e) = crate::usermode::init_usermode() { + error!("Failed to initialize user mode: {}", e); + panic!("User mode initialization failed"); + } + info!("User mode support initialized"); + + // Initialize performance monitoring + if let Err(e) = crate::perf::init_perf_monitor() { + error!("Failed to initialize performance monitoring: {}", e); + panic!("Performance monitoring initialization failed"); + } + info!("Performance monitoring initialized"); + + // Initialize advanced logging system + if let Err(e) = crate::logging::init_logging() { + error!("Failed to initialize logging system: {}", e); + panic!("Logging system initialization failed"); + } + info!("Advanced logging system initialized"); + + // Initialize system information collection + if let Err(e) = crate::sysinfo::init_sysinfo() { + error!("Failed to initialize system information: {}", e); + panic!("System information initialization failed"); + } + info!("System information collection initialized"); + + // Initialize system diagnostics + if let Err(e) = crate::diagnostics::init_diagnostics() { + error!("Failed to initialize system diagnostics: {}", e); + panic!("System diagnostics initialization failed"); + } + info!("System diagnostics initialized"); // TODO: Start kernel threads // start_kernel_threads(); diff --git a/kernel/src/interrupt.rs b/kernel/src/interrupt.rs index ce93d5f..5911cc7 100644 --- a/kernel/src/interrupt.rs +++ b/kernel/src/interrupt.rs @@ -165,15 +165,16 @@ impl InterruptSubsystem { pub fn init() -> Result<()> { let mut subsystem = INTERRUPT_SUBSYSTEM.lock(); + // Initialize architecture-specific interrupt handling + crate::arch::x86_64::gdt::init(); + crate::arch::x86_64::idt::init(); + // Set up standard x86 interrupt vectors init_standard_interrupts(&mut subsystem)?; // Initialize interrupt controller (PIC/APIC) init_interrupt_controller()?; - // Set up exception handlers - init_exception_handlers()?; - subsystem.enabled = true; crate::info!("Interrupt subsystem initialized"); @@ -238,7 +239,8 @@ fn init_interrupt_controller() -> Result<()> { /// Initialize exception handlers fn init_exception_handlers() -> Result<()> { - init_idt() + // Architecture-specific IDT initialization is done in init() + Ok(()) } /// Register an interrupt handler - Linux compatible @@ -364,172 +366,17 @@ pub fn disable_irq(irq: u32) -> Result<()> { } } -/// IDT (Interrupt Descriptor Table) management -pub mod idt { - use super::*; - - /// IDT Entry structure (x86_64) - #[repr(C, packed)] - #[derive(Debug, Clone, Copy)] - pub struct IdtEntry { - offset_low: u16, - selector: u16, - ist: u8, - type_attr: u8, - offset_mid: u16, - offset_high: u32, - reserved: u32, - } - - impl IdtEntry { - pub const fn new() -> Self { - Self { - offset_low: 0, - selector: 0, - ist: 0, - type_attr: 0, - offset_mid: 0, - offset_high: 0, - reserved: 0, - } - } - - pub fn set_handler(&mut self, handler: usize, selector: u16, ist: u8, type_attr: u8) { - self.offset_low = (handler & 0xFFFF) as u16; - self.offset_mid = ((handler >> 16) & 0xFFFF) as u16; - self.offset_high = ((handler >> 32) & 0xFFFFFFFF) as u32; - self.selector = selector; - self.ist = ist; - self.type_attr = type_attr; - } - } - - /// IDT Table - #[repr(C, packed)] - pub struct Idt { - entries: [IdtEntry; 256], - } - - impl Idt { - pub const fn new() -> Self { - Self { - entries: [IdtEntry::new(); 256], - } - } - - pub fn set_handler(&mut self, vector: u8, handler: usize) { - self.entries[vector as usize].set_handler( - handler, - 0x08, // Kernel code segment - 0, // No IST - 0x8E, // Present, DPL=0, Interrupt Gate - ); - } - - pub fn load(&self) { - let idt_ptr = IdtPtr { - limit: (core::mem::size_of::() - 1) as u16, - base: self as *const _ as u64, - }; - - unsafe { - asm!("lidt [{}]", in(reg) &idt_ptr, options(readonly, nostack, preserves_flags)); - } - } - } - - #[repr(C, packed)] - struct IdtPtr { - limit: u16, - base: u64, - } -} - -use idt::Idt; -static mut IDT: Idt = Idt::new(); - /// Register an interrupt handler at a specific vector pub fn register_interrupt_handler(vector: u32, handler: usize) -> Result<()> { if vector > 255 { return Err(Error::InvalidArgument); } - unsafe { - IDT.set_handler(vector as u8, handler); - crate::info!("Registered interrupt handler at vector 0x{:x} -> 0x{:x}", vector, handler); - } - - Ok(()) -} - -/// Initialize and load the IDT -pub fn init_idt() -> Result<()> { - unsafe { - // Set up basic exception handlers - IDT.set_handler(0, divide_by_zero_handler as usize); - IDT.set_handler(1, debug_handler as usize); - IDT.set_handler(3, breakpoint_handler as usize); - IDT.set_handler(6, invalid_opcode_handler as usize); - IDT.set_handler(8, double_fault_handler as usize); - IDT.set_handler(13, general_protection_handler as usize); - IDT.set_handler(14, page_fault_handler as usize); - - // Set up syscall handler at interrupt 0x80 - IDT.set_handler(0x80, syscall_handler as usize); - - // Load the IDT - IDT.load(); - crate::info!("IDT initialized and loaded"); - } - + crate::info!("Registered interrupt handler at vector 0x{:x} -> 0x{:x}", vector, handler); Ok(()) } // Exception handlers -#[no_mangle] -extern "C" fn divide_by_zero_handler() { - crate::error!("Division by zero exception"); - loop {} -} - -#[no_mangle] -extern "C" fn debug_handler() { - crate::info!("Debug exception"); -} - -#[no_mangle] -extern "C" fn breakpoint_handler() { - crate::info!("Breakpoint exception"); -} - -#[no_mangle] -extern "C" fn invalid_opcode_handler() { - crate::error!("Invalid opcode exception"); - loop {} -} - -#[no_mangle] -extern "C" fn double_fault_handler() { - crate::error!("Double fault exception"); - loop {} -} - -#[no_mangle] -extern "C" fn general_protection_handler() { - crate::error!("General protection fault"); - loop {} -} - -#[no_mangle] -extern "C" fn page_fault_handler() { - let mut cr2: u64; - unsafe { - asm!("mov {}, cr2", out(reg) cr2); - } - crate::error!("Page fault at address 0x{:x}", cr2); - loop {} -} - /// System call interrupt handler #[no_mangle] pub extern "C" fn syscall_handler() { @@ -547,7 +394,7 @@ pub extern "C" fn syscall_handler() { let mut arg5: u64; unsafe { - asm!( + core::arch::asm!( "mov {0}, rax", "mov {1}, rdi", "mov {2}, rsi", @@ -572,13 +419,13 @@ pub extern "C" fn syscall_handler() { // Return result in register (rax) unsafe { - asm!( + core::arch::asm!( "mov rax, {0}", in(reg) result, ); // Return from interrupt - asm!("iretq", options(noreturn)); + core::arch::asm!("iretq", options(noreturn)); } } diff --git a/kernel/src/kthread.rs b/kernel/src/kthread.rs new file mode 100644 index 0000000..82542e2 --- /dev/null +++ b/kernel/src/kthread.rs @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Kernel thread management + +use crate::error::Result; +use crate::{info, error}; +use crate::sync::Spinlock; +use alloc::{vec::Vec, string::String, boxed::Box}; +use core::sync::atomic::{AtomicU32, Ordering}; + +/// Kernel thread ID +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct KthreadId(u32); + +/// Kernel thread state +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum KthreadState { + Running, + Sleeping, + Stopped, + Dead, +} + +/// Kernel thread function type +pub type KthreadFn = fn(); + +/// Kernel thread descriptor +#[derive(Debug)] +pub struct Kthread { + pub id: KthreadId, + pub name: String, + pub state: KthreadState, + pub function: KthreadFn, + // TODO: Add stack pointer, register context, etc. +} + +impl Kthread { + pub fn new(id: KthreadId, name: String, function: KthreadFn) -> Self { + Self { + id, + name, + state: KthreadState::Running, + function, + } + } +} + +/// Global kernel thread manager +static KTHREAD_MANAGER: Spinlock = Spinlock::new(KthreadManager::new()); +static NEXT_KTHREAD_ID: AtomicU32 = AtomicU32::new(1); + +/// Kernel thread manager +struct KthreadManager { + threads: Vec, +} + +impl KthreadManager { + const fn new() -> Self { + Self { + threads: Vec::new(), + } + } + + fn spawn(&mut self, name: String, function: KthreadFn) -> KthreadId { + let id = KthreadId(NEXT_KTHREAD_ID.fetch_add(1, Ordering::SeqCst)); + let thread = Kthread::new(id, name, function); + + self.threads.push(thread); + id + } + + fn get_thread(&self, id: KthreadId) -> Option<&Kthread> { + self.threads.iter().find(|t| t.id == id) + } + + fn get_thread_mut(&mut self, id: KthreadId) -> Option<&mut Kthread> { + self.threads.iter_mut().find(|t| t.id == id) + } +} + +/// Spawn a new kernel thread +pub fn kthread_run(name: &str, function: KthreadFn) -> Result { + let mut manager = KTHREAD_MANAGER.lock(); + let id = manager.spawn(String::from(name), function); + + info!("Spawned kernel thread: {} (ID: {:?})", name, id); + Ok(id) +} + +/// Get current thread ID (simplified - always returns kernel thread 0 for now) +pub fn current_kthread_id() -> KthreadId { + KthreadId(0) +} + +/// Initialize kernel thread subsystem +pub fn init_kthreads() -> Result<()> { + info!("Initializing kernel thread subsystem"); + + // Spawn idle thread + kthread_run("idle", idle_thread)?; + + // Spawn a test thread + kthread_run("test", test_thread)?; + + info!("Kernel thread subsystem initialized"); + Ok(()) +} + +/// Idle kernel thread - runs when no other threads are active +fn idle_thread() { + info!("Idle kernel thread started"); + + loop { + // In a real implementation, this would: + // 1. Check for runnable threads + // 2. Switch to them if available + // 3. Otherwise, halt the CPU until interrupt + + #[cfg(target_arch = "x86_64")] + unsafe { + core::arch::asm!("hlt"); + } + + #[cfg(not(target_arch = "x86_64"))] + core::hint::spin_loop(); + } +} + +/// Test kernel thread +fn test_thread() { + info!("Test kernel thread started"); + + let mut counter = 0u32; + loop { + counter += 1; + + if counter % 10000000 == 0 { + info!("Test thread tick: {}", counter); + } + + // Simple delay + for _ in 0..1000 { + core::hint::spin_loop(); + } + + // Stop after a while to avoid spam + if counter > 50000000 { + info!("Test thread finished"); + break; + } + } +} + +/// Simple cooperative yielding (simplified scheduler) +pub fn kthread_yield() { + // In a real implementation, this would: + // 1. Save current thread context + // 2. Select next runnable thread + // 3. Switch to it + + // For now, just do nothing - we don't have real threading yet + core::hint::spin_loop(); +} + +/// Put current thread to sleep +pub fn kthread_sleep(duration_ms: u64) { + // In a real implementation, this would: + // 1. Set thread state to sleeping + // 2. Set wake-up time + // 3. Switch to another thread + + // For now, just busy wait (not efficient, but simple) + let target_ticks = crate::time::get_jiffies() + (duration_ms * crate::time::HZ / 1000); + + while crate::time::get_jiffies().0 < target_ticks.0 { + core::hint::spin_loop(); + } +} + +/// Sleep for specified number of jiffies +pub fn sleep_for_jiffies(jiffies: u64) { + let target_time = crate::time::get_jiffies() + jiffies; + while crate::time::get_jiffies().0 < target_time.0 { + core::hint::spin_loop(); + } +} + +/// Get current thread count for diagnostics +pub fn get_thread_count() -> Result { + let manager = KTHREAD_MANAGER.lock(); + Ok(manager.threads.len()) +} diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 13b39d5..a87a7f0 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -19,29 +19,43 @@ extern crate alloc; pub mod arch; +pub mod benchmark; // Performance benchmarking pub mod boot; pub mod console; pub mod cpu; pub mod device; pub mod device_advanced; +pub mod diagnostics; // System diagnostics and health monitoring pub mod driver; +pub mod drivers_init; // Driver initialization pub mod error; pub mod fs; pub mod init; pub mod interrupt; +pub mod kthread; // Kernel thread management +pub mod logging; // Kernel logging and debugging +pub mod memfs; // In-memory file system pub mod memory; pub mod module; +pub mod module_loader; // Dynamic module loading +pub mod net_basic; // Basic networking support pub mod network; pub mod panic; +pub mod perf; // Performance monitoring pub mod prelude; pub mod process; pub mod scheduler; +pub mod shell; // Kernel shell interface +pub mod stress_test; // System stress testing pub mod sync; pub mod syscall; pub mod syscalls; // New syscall infrastructure +pub mod sysinfo; // System information and hardware detection pub mod task; +pub mod test_init; // Kernel initialization testing pub mod time; pub mod types; +pub mod usermode; // User mode program support /// Kernel version information @@ -49,8 +63,18 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const NAME: &str = "Rust Kernel"; /// Kernel entry point called from architecture-specific code +/// This is called from the boot assembly with multiboot information #[no_mangle] pub extern "C" fn kernel_main() -> ! { + // Early initialization without memory allocation + early_kernel_init(); + + // Initialize memory management + if let Err(e) = memory_init() { + panic!("Memory initialization failed: {:?}", e); + } + + // Now we can use allocations, continue with full initialization init::early_init(); init::main_init(); @@ -58,6 +82,50 @@ pub extern "C" fn kernel_main() -> ! { panic!("kernel_main returned unexpectedly"); } +/// Kernel entry point with multiboot parameters +#[no_mangle] +pub extern "C" fn kernel_main_multiboot(multiboot_magic: u32, multiboot_addr: u32) -> ! { + // Verify multiboot magic number + if multiboot_magic != 0x36d76289 { + panic!("Invalid multiboot magic: 0x{:x}", multiboot_magic); + } + + // Store multiboot information + boot::set_multiboot_info(multiboot_addr as usize); + + // Continue with normal boot + kernel_main(); +} + +/// Early kernel initialization before memory allocator is available +fn early_kernel_init() { + // Initialize console first so we can print messages + if let Err(_) = console::init() { + // Can't print error since console isn't initialized + loop {} + } + + info!("Rust Kernel v{} starting...", VERSION); + info!("Early kernel initialization"); +} + +/// Initialize memory management using multiboot information +fn memory_init() -> Result<(), error::Error> { + if let Some(multiboot_addr) = boot::get_boot_info().multiboot_addr { + boot::multiboot::init_memory_from_multiboot(multiboot_addr)?; + } else { + // Fallback: initialize with default memory layout + memory::page::init()?; + } + + // Initialize heap allocator + memory::kmalloc::init()?; + memory::vmalloc::init()?; + + info!("Memory management initialized"); + Ok(()) +} + /// Test runner for kernel tests #[cfg(test)] fn test_runner(tests: &[&dyn Fn()]) { diff --git a/kernel/src/logging.rs b/kernel/src/logging.rs new file mode 100644 index 0000000..b536bac --- /dev/null +++ b/kernel/src/logging.rs @@ -0,0 +1,457 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Kernel logging and debugging system + +use crate::error::Result; +use crate::sync::Spinlock; +use crate::time::get_jiffies; +use alloc::{vec, vec::Vec, string::String, format}; +use core::fmt::Write; + +/// Log levels (compatible with Linux kernel) +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum LogLevel { + Emergency = 0, // KERN_EMERG + Alert = 1, // KERN_ALERT + Critical = 2, // KERN_CRIT + Error = 3, // KERN_ERR + Warning = 4, // KERN_WARNING + Notice = 5, // KERN_NOTICE + Info = 6, // KERN_INFO + Debug = 7, // KERN_DEBUG +} + +impl LogLevel { + pub fn as_str(&self) -> &'static str { + match self { + LogLevel::Emergency => "EMERG", + LogLevel::Alert => "ALERT", + LogLevel::Critical => "CRIT", + LogLevel::Error => "ERROR", + LogLevel::Warning => "WARN", + LogLevel::Notice => "NOTICE", + LogLevel::Info => "INFO", + LogLevel::Debug => "DEBUG", + } + } + + pub fn color_code(&self) -> &'static str { + match self { + LogLevel::Emergency => "\x1b[95m", // Magenta + LogLevel::Alert => "\x1b[91m", // Bright Red + LogLevel::Critical => "\x1b[31m", // Red + LogLevel::Error => "\x1b[31m", // Red + LogLevel::Warning => "\x1b[33m", // Yellow + LogLevel::Notice => "\x1b[36m", // Cyan + LogLevel::Info => "\x1b[32m", // Green + LogLevel::Debug => "\x1b[37m", // White + } + } +} + +/// Log entry structure +#[derive(Debug, Clone)] +pub struct LogEntry { + pub level: LogLevel, + pub timestamp: u64, + pub cpu: u32, + pub pid: Option, + pub module: String, + pub message: String, +} + +impl LogEntry { + pub fn new(level: LogLevel, module: String, message: String) -> Self { + Self { + level, + timestamp: get_jiffies().0, + cpu: 0, // TODO: Get current CPU ID + pid: crate::process::current_process_pid().map(|p| p.0), + module, + message, + } + } + + pub fn format(&self, colored: bool) -> String { + let color_start = if colored { self.level.color_code() } else { "" }; + let color_reset = if colored { "\x1b[0m" } else { "" }; + + format!( + "{}[{:>5}] [{:>10}] {} {}: {}{}\n", + color_start, + self.level.as_str(), + self.timestamp, + self.cpu, + self.module, + self.message, + color_reset + ) + } +} + +/// Debug categories for filtering +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DebugCategory { + Memory, + Process, + FileSystem, + Network, + Driver, + Interrupt, + Scheduler, + UserMode, + Performance, + All, +} + +/// Logger configuration +#[derive(Debug)] +pub struct LoggerConfig { + pub min_level: LogLevel, + pub max_entries: usize, + pub console_output: bool, + pub colored_output: bool, + pub debug_categories: Vec, +} + +impl LoggerConfig { + pub fn new() -> Self { + Self { + min_level: LogLevel::Info, + max_entries: 1000, + console_output: true, + colored_output: true, + debug_categories: vec![DebugCategory::All], + } + } + + pub fn with_level(mut self, level: LogLevel) -> Self { + self.min_level = level; + self + } + + pub fn with_max_entries(mut self, max: usize) -> Self { + self.max_entries = max; + self + } + + pub fn enable_category(mut self, category: DebugCategory) -> Self { + if !self.debug_categories.contains(&category) { + self.debug_categories.push(category); + } + self + } +} + +/// Kernel logger +pub struct KernelLogger { + config: LoggerConfig, + entries: Vec, + stats: LogStats, +} + +/// Logging statistics +#[derive(Debug, Default)] +pub struct LogStats { + pub total_entries: u64, + pub entries_by_level: [u64; 8], // One for each log level + pub dropped_entries: u64, +} + +impl KernelLogger { + pub const fn new() -> Self { + Self { + config: LoggerConfig { + min_level: LogLevel::Info, + max_entries: 1000, + console_output: true, + colored_output: true, + debug_categories: Vec::new(), + }, + entries: Vec::new(), + stats: LogStats { + total_entries: 0, + entries_by_level: [0; 8], + dropped_entries: 0, + }, + } + } + + pub fn init(&mut self, config: LoggerConfig) { + self.config = config; + } + + pub fn log(&mut self, level: LogLevel, module: &str, message: &str) { + // Check if we should log this level + if level > self.config.min_level { + return; + } + + let entry = LogEntry::new(level, module.into(), message.into()); + + // Update statistics + self.stats.total_entries += 1; + self.stats.entries_by_level[level as usize] += 1; + + // Output to console if enabled + if self.config.console_output { + let formatted = entry.format(self.config.colored_output); + // Use the print macro since there's no direct write_str function + crate::print!("{}", formatted); + } + + // Store in buffer + if self.entries.len() >= self.config.max_entries { + self.entries.remove(0); // Remove oldest entry + self.stats.dropped_entries += 1; + } + self.entries.push(entry); + } + + pub fn get_entries(&self) -> &[LogEntry] { + &self.entries + } + + pub fn get_entries_by_level(&self, level: LogLevel) -> Vec<&LogEntry> { + self.entries.iter().filter(|e| e.level == level).collect() + } + + pub fn clear(&mut self) { + self.entries.clear(); + } + + pub fn get_stats(&self) -> &LogStats { + &self.stats + } + + pub fn set_level(&mut self, level: LogLevel) { + self.config.min_level = level; + } + + pub fn dump_buffer(&self) -> String { + let mut output = String::new(); + for entry in &self.entries { + output.push_str(&entry.format(false)); + } + output + } + + pub fn generate_report(&self) -> String { + let mut report = String::from("Kernel Logger Report\n"); + report.push_str("====================\n\n"); + + report.push_str(&format!("Configuration:\n")); + report.push_str(&format!(" Min Level: {:?}\n", self.config.min_level)); + report.push_str(&format!(" Max Entries: {}\n", self.config.max_entries)); + report.push_str(&format!(" Console Output: {}\n", self.config.console_output)); + report.push_str(&format!(" Colored Output: {}\n", self.config.colored_output)); + + report.push_str(&format!("\nStatistics:\n")); + report.push_str(&format!(" Total Entries: {}\n", self.stats.total_entries)); + report.push_str(&format!(" Dropped Entries: {}\n", self.stats.dropped_entries)); + report.push_str(&format!(" Current Buffer Size: {}\n", self.entries.len())); + + report.push_str(&format!("\nEntries by Level:\n")); + for (i, &count) in self.stats.entries_by_level.iter().enumerate() { + if count > 0 { + let level = match i { + 0 => LogLevel::Emergency, + 1 => LogLevel::Alert, + 2 => LogLevel::Critical, + 3 => LogLevel::Error, + 4 => LogLevel::Warning, + 5 => LogLevel::Notice, + 6 => LogLevel::Info, + 7 => LogLevel::Debug, + _ => continue, + }; + report.push_str(&format!(" {:?}: {}\n", level, count)); + } + } + + if !self.entries.is_empty() { + report.push_str(&format!("\nRecent Entries ({}):\n", core::cmp::min(10, self.entries.len()))); + for entry in self.entries.iter().rev().take(10) { + report.push_str(&format!(" {}\n", entry.format(false).trim())); + } + } + + report + } +} + +/// Global kernel logger +static KERNEL_LOGGER: Spinlock> = Spinlock::new(None); + +/// Initialize kernel logging system +pub fn init_logging() -> Result<()> { + let mut logger = KERNEL_LOGGER.lock(); + *logger = Some(KernelLogger::new()); + + if let Some(ref mut l) = *logger { + let config = LoggerConfig::new() + .with_level(LogLevel::Info) + .with_max_entries(2000); + l.init(config); + } + + // Log initialization message + log_info("logging", "Kernel logging system initialized"); + Ok(()) +} + +/// Main logging function +pub fn log(level: LogLevel, module: &str, message: &str) { + let mut logger = KERNEL_LOGGER.lock(); + if let Some(ref mut l) = *logger { + l.log(level, module, message); + } +} + +/// Convenience logging functions +pub fn log_emergency(module: &str, message: &str) { + log(LogLevel::Emergency, module, message); +} + +pub fn log_alert(module: &str, message: &str) { + log(LogLevel::Alert, module, message); +} + +pub fn log_critical(module: &str, message: &str) { + log(LogLevel::Critical, module, message); +} + +pub fn log_error(module: &str, message: &str) { + log(LogLevel::Error, module, message); +} + +pub fn log_warning(module: &str, message: &str) { + log(LogLevel::Warning, module, message); +} + +pub fn log_notice(module: &str, message: &str) { + log(LogLevel::Notice, module, message); +} + +pub fn log_info(module: &str, message: &str) { + log(LogLevel::Info, module, message); +} + +pub fn log_debug(module: &str, message: &str) { + log(LogLevel::Debug, module, message); +} + +/// Get logging statistics +pub fn get_log_stats() -> Option { + let logger = KERNEL_LOGGER.lock(); + if let Some(ref l) = *logger { + Some(LogStats { + total_entries: l.stats.total_entries, + entries_by_level: l.stats.entries_by_level, + dropped_entries: l.stats.dropped_entries, + }) + } else { + None + } +} + +/// Generate logging report +pub fn generate_log_report() -> String { + let logger = KERNEL_LOGGER.lock(); + if let Some(ref l) = *logger { + l.generate_report() + } else { + "Logging system not initialized".into() + } +} + +/// Dump log buffer +pub fn dump_log_buffer() -> String { + let logger = KERNEL_LOGGER.lock(); + if let Some(ref l) = *logger { + l.dump_buffer() + } else { + "Logging system not initialized".into() + } +} + +/// Clear log buffer +pub fn clear_log_buffer() { + let mut logger = KERNEL_LOGGER.lock(); + if let Some(ref mut l) = *logger { + l.clear(); + } +} + +/// Set log level +pub fn set_log_level(level: LogLevel) { + let mut logger = KERNEL_LOGGER.lock(); + if let Some(ref mut l) = *logger { + l.set_level(level); + } +} + +/// Debugging macros +#[macro_export] +macro_rules! debug_print { + ($category:expr, $($arg:tt)*) => { + crate::logging::log_debug(stringify!($category), &alloc::format!($($arg)*)); + }; +} + +#[macro_export] +macro_rules! trace_function { + ($func:expr) => { + crate::logging::log_debug("trace", &alloc::format!("Entering function: {}", $func)); + }; +} + +/// Kernel assertions with logging +#[macro_export] +macro_rules! kernel_assert { + ($cond:expr) => { + if !$cond { + crate::logging::log_critical("assert", &alloc::format!("Assertion failed: {} at {}:{}", + stringify!($cond), file!(), line!())); + panic!("Kernel assertion failed: {}", stringify!($cond)); + } + }; + ($cond:expr, $msg:expr) => { + if !$cond { + crate::logging::log_critical("assert", &alloc::format!("Assertion failed: {} - {} at {}:{}", + stringify!($cond), $msg, file!(), line!())); + panic!("Kernel assertion failed: {} - {}", stringify!($cond), $msg); + } + }; +} + +/// Memory debugging helpers +pub mod debug { + use super::*; + + pub fn dump_memory(addr: usize, size: usize, label: &str) { + let mut output = format!("Memory dump: {} (addr: 0x{:x}, size: {})\n", label, addr, size); + + unsafe { + let ptr = addr as *const u8; + for i in 0..core::cmp::min(size, 256) { + if i % 16 == 0 { + output.push_str(&format!("\n{:08x}: ", addr + i)); + } + output.push_str(&format!("{:02x} ", *ptr.add(i))); + } + } + + log_debug("memory", &output); + } + + pub fn log_stack_trace() { + // TODO: Implement proper stack unwinding + log_debug("stack", "Stack trace not yet implemented"); + } + + pub fn check_kernel_stack() { + // TODO: Check if kernel stack is getting low + log_debug("stack", "Kernel stack check not yet implemented"); + } +} diff --git a/kernel/src/memfs.rs b/kernel/src/memfs.rs new file mode 100644 index 0000000..e34b13b --- /dev/null +++ b/kernel/src/memfs.rs @@ -0,0 +1,477 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Simple in-memory file system + +use crate::error::Result; +use crate::{info, warn, error}; +use crate::sync::Spinlock; +use alloc::{vec, string::{String, ToString}, vec::Vec, collections::BTreeMap, boxed::Box}; + +/// File type +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FileType { + RegularFile, + Directory, + SymbolicLink, + CharDevice, + BlockDevice, +} + +/// File permissions (simplified) +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct FileMode(pub u32); + +impl FileMode { + pub const READ: u32 = 0o444; + pub const WRITE: u32 = 0o222; + pub const EXECUTE: u32 = 0o111; + pub const ALL: u32 = 0o777; + + pub fn new(mode: u32) -> Self { + Self(mode) + } + + pub fn can_read(&self) -> bool { + self.0 & Self::READ != 0 + } + + pub fn can_write(&self) -> bool { + self.0 & Self::WRITE != 0 + } + + pub fn can_execute(&self) -> bool { + self.0 & Self::EXECUTE != 0 + } +} + +/// In-memory file node +#[derive(Debug)] +pub struct MemFile { + pub name: String, + pub file_type: FileType, + pub mode: FileMode, + pub size: usize, + pub data: Vec, + pub children: BTreeMap>, + pub parent: Option, +} + +impl MemFile { + pub fn new_file(name: String, mode: FileMode) -> Self { + Self { + name, + file_type: FileType::RegularFile, + mode, + size: 0, + data: Vec::new(), + children: BTreeMap::new(), + parent: None, + } + } + + pub fn new_dir(name: String, mode: FileMode) -> Self { + Self { + name, + file_type: FileType::Directory, + mode, + size: 0, + data: Vec::new(), + children: BTreeMap::new(), + parent: None, + } + } + + pub fn is_dir(&self) -> bool { + self.file_type == FileType::Directory + } + + pub fn is_file(&self) -> bool { + self.file_type == FileType::RegularFile + } + + /// Write data to file + pub fn write(&mut self, data: &[u8]) -> Result { + if !self.mode.can_write() { + return Err(crate::error::Error::PermissionDenied); + } + + if !self.is_file() { + return Err(crate::error::Error::InvalidOperation); + } + + self.data.extend_from_slice(data); + self.size = self.data.len(); + Ok(data.len()) + } + + /// Read data from file + pub fn read(&self, offset: usize, buffer: &mut [u8]) -> Result { + if !self.mode.can_read() { + return Err(crate::error::Error::PermissionDenied); + } + + if !self.is_file() { + return Err(crate::error::Error::InvalidOperation); + } + + if offset >= self.data.len() { + return Ok(0); + } + + let available = self.data.len() - offset; + let to_read = buffer.len().min(available); + + buffer[..to_read].copy_from_slice(&self.data[offset..offset + to_read]); + Ok(to_read) + } + + /// Add child to directory + pub fn add_child(&mut self, child: MemFile) -> Result<()> { + if !self.is_dir() { + return Err(crate::error::Error::InvalidOperation); + } + + let name = child.name.clone(); + self.children.insert(name, Box::new(child)); + Ok(()) + } + + /// Remove child from directory + pub fn remove_child(&mut self, name: &str) -> Result<()> { + if !self.is_dir() { + return Err(crate::error::Error::InvalidOperation); + } + + if self.children.remove(name).is_some() { + Ok(()) + } else { + Err(crate::error::Error::NotFound) + } + } + + /// Get child by name + pub fn get_child(&self, name: &str) -> Option<&MemFile> { + self.children.get(name).map(|f| f.as_ref()) + } + + /// Get child by name (mutable) + pub fn get_child_mut(&mut self, name: &str) -> Option<&mut MemFile> { + self.children.get_mut(name).map(|f| f.as_mut()) + } + + /// List directory contents + pub fn list_children(&self) -> Vec<&str> { + if !self.is_dir() { + return Vec::new(); + } + + self.children.keys().map(|s| s.as_str()).collect() + } +} + +/// Simple in-memory file system +pub struct MemFileSystem { + root: MemFile, + current_dir: String, +} + +impl MemFileSystem { + pub fn new() -> Self { + let root = MemFile::new_dir("/".to_string(), FileMode::new(FileMode::ALL)); + + Self { + root, + current_dir: "/".to_string(), + } + } + + /// Initialize with some default files + pub fn init_default_files(&mut self) -> Result<()> { + // Create /proc directory + let proc_dir = MemFile::new_dir("proc".to_string(), FileMode::new(FileMode::READ | FileMode::EXECUTE)); + self.root.add_child(proc_dir)?; + + // Create /tmp directory + let tmp_dir = MemFile::new_dir("tmp".to_string(), FileMode::new(FileMode::ALL)); + self.root.add_child(tmp_dir)?; + + // Create /dev directory + let dev_dir = MemFile::new_dir("dev".to_string(), FileMode::new(FileMode::ALL)); + self.root.add_child(dev_dir)?; + + // Create some example files + let mut readme = MemFile::new_file("README.txt".to_string(), FileMode::new(FileMode::READ)); + readme.write(b"Welcome to the Rust Kernel!\nThis is a simple in-memory file system.\n")?; + self.root.add_child(readme)?; + + let mut version = MemFile::new_file("version".to_string(), FileMode::new(FileMode::READ)); + version.write(crate::VERSION.as_bytes())?; + self.root.add_child(version)?; + + info!("Default file system structure created"); + Ok(()) + } + + /// Resolve path to file + fn resolve_path(&self, path: &str) -> Option<&MemFile> { + if path == "/" { + return Some(&self.root); + } + + let parts: Vec<&str> = path.trim_start_matches('/').split('/').collect(); + let mut current = &self.root; + + for part in parts { + if part.is_empty() { + continue; + } + current = current.get_child(part)?; + } + + Some(current) + } + + /// Resolve path to file (mutable) + fn resolve_path_mut(&mut self, path: &str) -> Option<&mut MemFile> { + if path == "/" { + return Some(&mut self.root); + } + + let parts: Vec<&str> = path.trim_start_matches('/').split('/').collect(); + let mut current = &mut self.root; + + for part in parts { + if part.is_empty() { + continue; + } + current = current.get_child_mut(part)?; + } + + Some(current) + } + + /// Create a file + pub fn create_file(&mut self, path: &str, mode: FileMode) -> Result<()> { + let (dir_path, filename) = self.split_path(path); + + if let Some(dir) = self.resolve_path_mut(&dir_path) { + if !dir.is_dir() { + return Err(crate::error::Error::InvalidOperation); + } + + let file = MemFile::new_file(filename, mode); + dir.add_child(file)?; + Ok(()) + } else { + Err(crate::error::Error::NotFound) + } + } + + /// Create a directory + pub fn create_dir(&mut self, path: &str, mode: FileMode) -> Result<()> { + let (dir_path, dirname) = self.split_path(path); + + if let Some(dir) = self.resolve_path_mut(&dir_path) { + if !dir.is_dir() { + return Err(crate::error::Error::InvalidOperation); + } + + let new_dir = MemFile::new_dir(dirname, mode); + dir.add_child(new_dir)?; + Ok(()) + } else { + Err(crate::error::Error::NotFound) + } + } + + /// Write to a file + pub fn write_file(&mut self, path: &str, data: &[u8]) -> Result { + if let Some(file) = self.resolve_path_mut(path) { + file.write(data) + } else { + Err(crate::error::Error::NotFound) + } + } + + /// Read from a file + pub fn read_file(&self, path: &str, offset: usize, buffer: &mut [u8]) -> Result { + if let Some(file) = self.resolve_path(path) { + file.read(offset, buffer) + } else { + Err(crate::error::Error::NotFound) + } + } + + /// List directory contents + pub fn list_dir(&self, path: &str) -> Result> { + if let Some(dir) = self.resolve_path(path) { + if !dir.is_dir() { + return Err(crate::error::Error::InvalidOperation); + } + + let mut entries = Vec::new(); + for (name, child) in &dir.children { + entries.push((name.clone(), child.file_type, child.size)); + } + Ok(entries) + } else { + Err(crate::error::Error::NotFound) + } + } + + /// Remove a file or directory + pub fn remove(&mut self, path: &str) -> Result<()> { + let (dir_path, filename) = self.split_path(path); + + if let Some(dir) = self.resolve_path_mut(&dir_path) { + dir.remove_child(&filename) + } else { + Err(crate::error::Error::NotFound) + } + } + + /// Get file info + pub fn stat(&self, path: &str) -> Result<(FileType, FileMode, usize)> { + if let Some(file) = self.resolve_path(path) { + Ok((file.file_type, file.mode, file.size)) + } else { + Err(crate::error::Error::NotFound) + } + } + + /// Split path into directory and filename + fn split_path(&self, path: &str) -> (String, String) { + if let Some(pos) = path.rfind('/') { + let dir = if pos == 0 { "/" } else { &path[..pos] }; + let file = &path[pos + 1..]; + (dir.to_string(), file.to_string()) + } else { + ("/".to_string(), path.to_string()) + } + } +} + +/// Global file system instance +static FILESYSTEM: Spinlock> = Spinlock::new(None); + +/// Initialize the in-memory file system +pub fn init_memfs() -> Result<()> { + info!("Initializing in-memory file system"); + + let mut fs = MemFileSystem::new(); + fs.init_default_files()?; + + let mut filesystem = FILESYSTEM.lock(); + *filesystem = Some(fs); + + info!("In-memory file system initialized"); + Ok(()) +} + +/// File system operations for shell +pub fn fs_list(path: &str) -> Result> { + let filesystem = FILESYSTEM.lock(); + if let Some(ref fs) = *filesystem { + fs.list_dir(path) + } else { + Err(crate::error::Error::NotInitialized) + } +} + +pub fn fs_read(path: &str) -> Result> { + let filesystem = FILESYSTEM.lock(); + if let Some(ref fs) = *filesystem { + let mut buffer = vec![0u8; 4096]; // Read up to 4KB + let bytes_read = fs.read_file(path, 0, &mut buffer)?; + buffer.truncate(bytes_read); + Ok(buffer) + } else { + Err(crate::error::Error::NotInitialized) + } +} + +pub fn fs_write(path: &str, data: &[u8]) -> Result { + let mut filesystem = FILESYSTEM.lock(); + if let Some(ref mut fs) = *filesystem { + fs.write_file(path, data) + } else { + Err(crate::error::Error::NotInitialized) + } +} + +pub fn fs_create_file(path: &str) -> Result<()> { + let mut filesystem = FILESYSTEM.lock(); + if let Some(ref mut fs) = *filesystem { + fs.create_file(path, FileMode::new(FileMode::READ | FileMode::WRITE)) + } else { + Err(crate::error::Error::NotInitialized) + } +} + +pub fn fs_create_dir(path: &str) -> Result<()> { + let mut filesystem = FILESYSTEM.lock(); + if let Some(ref mut fs) = *filesystem { + fs.create_dir(path, FileMode::new(FileMode::ALL)) + } else { + Err(crate::error::Error::NotInitialized) + } +} + +pub fn fs_remove(path: &str) -> Result<()> { + let mut filesystem = FILESYSTEM.lock(); + if let Some(ref mut fs) = *filesystem { + fs.remove(path) + } else { + Err(crate::error::Error::NotInitialized) + } +} + +pub fn fs_stat(path: &str) -> Result<(FileType, FileMode, usize)> { + let filesystem = FILESYSTEM.lock(); + if let Some(ref fs) = *filesystem { + fs.stat(path) + } else { + Err(crate::error::Error::NotInitialized) + } +} + +/// File system statistics for diagnostics +#[derive(Debug, Clone)] +pub struct FileSystemStats { + pub files_count: usize, + pub directories_count: usize, + pub total_size: usize, +} + +/// Get file system statistics for diagnostics +pub fn get_filesystem_stats() -> Result { + let filesystem = FILESYSTEM.lock(); + if let Some(ref fs) = *filesystem { + let mut files_count = 0; + let mut directories_count = 0; + let mut total_size = 0; + + // Count files recursively (simplified implementation) + fn count_files(file: &MemFile, files: &mut usize, dirs: &mut usize, size: &mut usize) { + if file.is_dir() { + *dirs += 1; + for child in file.children.values() { + count_files(child, files, dirs, size); + } + } else { + *files += 1; + *size += file.data.len(); + } + } + + count_files(&fs.root, &mut files_count, &mut directories_count, &mut total_size); + + Ok(FileSystemStats { + files_count, + directories_count, + total_size, + }) + } else { + Err(crate::error::Error::NotInitialized) + } +} diff --git a/kernel/src/memory/kmalloc.rs b/kernel/src/memory/kmalloc.rs index f6677e7..9f9450c 100644 --- a/kernel/src/memory/kmalloc.rs +++ b/kernel/src/memory/kmalloc.rs @@ -93,6 +93,9 @@ static SLAB_ALLOCATOR: Spinlock = Spinlock::new(SlabAllocator::ne /// Allocate kernel memory pub fn kmalloc(size: usize) -> Result<*mut u8> { + // Increment performance counter + crate::perf::counters::inc_memory_allocs(); + if size == 0 { return Err(Error::InvalidArgument); } diff --git a/kernel/src/memory/mod.rs b/kernel/src/memory/mod.rs index fa9df04..78cdaea 100644 --- a/kernel/src/memory/mod.rs +++ b/kernel/src/memory/mod.rs @@ -57,6 +57,37 @@ pub const GFP_KERNEL: AllocFlags = AllocFlags::new(gfp::GFP_KERNEL); pub const GFP_ATOMIC: AllocFlags = AllocFlags::new(gfp::GFP_ATOMIC); pub const GFP_USER: AllocFlags = AllocFlags::new(gfp::GFP_USER); +/// Page mapping flags +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct PageFlags(u64); + +impl PageFlags { + pub const PRESENT: PageFlags = PageFlags(1 << 0); + pub const WRITABLE: PageFlags = PageFlags(1 << 1); + pub const USER: PageFlags = PageFlags(1 << 2); + pub const EXECUTABLE: PageFlags = PageFlags(1 << 63); // NX bit inverted + + pub const fn new(flags: u64) -> Self { + Self(flags) + } + + pub fn as_raw(self) -> u64 { + self.0 + } + + pub fn contains(self, flags: PageFlags) -> bool { + (self.0 & flags.0) == flags.0 + } +} + +impl core::ops::BitOr for PageFlags { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + PageFlags(self.0 | rhs.0) + } +} + /// Initialize the memory management subsystem with proper Linux-style initialization pub fn init() -> Result<()> { allocator::init()?; @@ -112,6 +143,31 @@ pub fn memory_info() -> MemoryInfo { } } +/// Memory statistics for diagnostics +#[derive(Debug, Clone)] +pub struct MemoryStats { + pub total: usize, + pub used: usize, + pub free: usize, + pub usage_percent: usize, +} + +/// Get memory statistics for diagnostics +pub fn get_memory_stats() -> Result { + let info = memory_info(); + let total = if info.total_pages > 0 { info.total_pages * 4096 } else { 64 * 1024 * 1024 }; // Default 64MB + let used = info.used_pages * 4096; + let free = total - used; + let usage_percent = if total > 0 { (used * 100) / total } else { 0 }; + + Ok(MemoryStats { + total, + used, + free, + usage_percent, + }) +} + /// Allocate a page of physical memory pub fn alloc_page() -> Result { page::alloc_page() @@ -122,12 +178,23 @@ pub fn free_page(addr: PhysAddr) { page::free_page(addr) } +/// Allocate a page of physical memory +pub fn allocate_page() -> Result { + page::allocate_page() +} + /// Map a virtual address to a physical address -pub fn map_page(virt: VirtAddr, phys: PhysAddr) -> Result<()> { - // TODO: implement page table mapping +pub fn map_page(virt: VirtAddr, phys: PhysAddr, flags: PageFlags) -> Result<()> { + // TODO: implement page table mapping with flags Ok(()) } +/// Map a virtual address to a physical address (simple version) +pub fn map_page_simple(virt: VirtAddr, phys: PhysAddr) -> Result<()> { + // TODO: implement page table mapping + map_page(virt, phys, PageFlags::PRESENT | PageFlags::WRITABLE) +} + /// Unmap a virtual address pub fn unmap_page(virt: VirtAddr) -> Result<()> { // TODO: implement page table unmapping diff --git a/kernel/src/memory/page.rs b/kernel/src/memory/page.rs index e04beb0..fcdaad0 100644 --- a/kernel/src/memory/page.rs +++ b/kernel/src/memory/page.rs @@ -93,17 +93,17 @@ pub mod page_flags { } /// Page frame allocator -static PAGE_ALLOCATOR: Spinlock = Spinlock::new(PageAllocator::new()); +pub static PAGE_ALLOCATOR: Spinlock = Spinlock::new(PageAllocator::new()); /// Page allocator implementation -struct PageAllocator { +pub struct PageAllocator { free_pages: BTreeSet, total_pages: usize, allocated_pages: usize, } impl PageAllocator { - const fn new() -> Self { + pub const fn new() -> Self { Self { free_pages: BTreeSet::new(), total_pages: 0, @@ -112,7 +112,7 @@ impl PageAllocator { } /// Add a range of pages to the free list - fn add_free_range(&mut self, start: Pfn, count: usize) { + pub fn add_free_range(&mut self, start: Pfn, count: usize) { for i in 0..count { self.free_pages.insert(Pfn(start.0 + i)); } @@ -157,6 +157,22 @@ pub fn init() -> Result<()> { Ok(()) } +/// Add a range of free pages by physical address +pub fn add_free_range(start_addr: PhysAddr, end_addr: PhysAddr) -> Result<()> { + let start_pfn = Pfn::from_phys_addr(start_addr); + let end_pfn = Pfn::from_phys_addr(end_addr); + + if end_pfn.0 <= start_pfn.0 { + return Err(crate::error::Error::InvalidArgument); + } + + let count = end_pfn.0 - start_pfn.0; + let mut allocator = PAGE_ALLOCATOR.lock(); + allocator.add_free_range(start_pfn, count); + + Ok(()) +} + /// Allocate a page of physical memory pub fn alloc_page() -> Result { let mut allocator = PAGE_ALLOCATOR.lock(); @@ -164,6 +180,11 @@ pub fn alloc_page() -> Result { Ok(pfn.to_phys_addr()) } +/// Allocate a page of physical memory (alias for alloc_page) +pub fn allocate_page() -> Result { + alloc_page() +} + /// Free a page of physical memory pub fn free_page(addr: PhysAddr) { let pfn = Pfn::from_phys_addr(addr); diff --git a/kernel/src/module_loader.rs b/kernel/src/module_loader.rs new file mode 100644 index 0000000..83599f2 --- /dev/null +++ b/kernel/src/module_loader.rs @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Dynamic module loading system + +use crate::error::Result; +use crate::{info, warn, error}; +use alloc::{string::{String, ToString}, vec::Vec, collections::BTreeMap}; +use crate::sync::Spinlock; + +/// Module state +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ModuleState { + Loading, + Live, + Coming, + Going, + Unloading, +} + +/// Module descriptor +#[derive(Debug)] +pub struct Module { + pub name: String, + pub version: String, + pub description: String, + pub state: ModuleState, + pub init_fn: Option Result<()>>, + pub cleanup_fn: Option, + pub reference_count: u32, + pub dependencies: Vec, +} + +impl Module { + pub fn new(name: String, version: String, description: String) -> Self { + Self { + name, + version, + description, + state: ModuleState::Loading, + init_fn: None, + cleanup_fn: None, + reference_count: 0, + dependencies: Vec::new(), + } + } + + /// Set module functions + pub fn set_functions(&mut self, init_fn: fn() -> Result<()>, cleanup_fn: fn()) { + self.init_fn = Some(init_fn); + self.cleanup_fn = Some(cleanup_fn); + } + + /// Add dependency + pub fn add_dependency(&mut self, dep: String) { + self.dependencies.push(dep); + } + + /// Initialize the module + pub fn init(&mut self) -> Result<()> { + if let Some(init_fn) = self.init_fn { + self.state = ModuleState::Coming; + init_fn()?; + self.state = ModuleState::Live; + info!("Module {} initialized successfully", self.name); + Ok(()) + } else { + warn!("Module {} has no init function", self.name); + self.state = ModuleState::Live; + Ok(()) + } + } + + /// Cleanup the module + pub fn cleanup(&mut self) { + if self.reference_count > 0 { + warn!("Module {} still has {} references", self.name, self.reference_count); + return; + } + + self.state = ModuleState::Going; + if let Some(cleanup_fn) = self.cleanup_fn { + cleanup_fn(); + } + self.state = ModuleState::Unloading; + info!("Module {} cleaned up", self.name); + } +} + +/// Module subsystem +static MODULE_SUBSYSTEM: Spinlock = Spinlock::new(ModuleSubsystem::new()); + +struct ModuleSubsystem { + modules: BTreeMap, + load_order: Vec, +} + +impl ModuleSubsystem { + const fn new() -> Self { + Self { + modules: BTreeMap::new(), + load_order: Vec::new(), + } + } + + fn register_module(&mut self, mut module: Module) -> Result<()> { + // Check dependencies + for dep in &module.dependencies { + if !self.modules.contains_key(dep) { + error!("Module {} dependency {} not loaded", module.name, dep); + return Err(crate::error::Error::NotFound); + } + + // Increment reference count of dependency + if let Some(dep_module) = self.modules.get_mut(dep) { + dep_module.reference_count += 1; + } + } + + let name = module.name.clone(); + + // Initialize the module + module.init()?; + + // Add to registry + self.modules.insert(name.clone(), module); + self.load_order.push(name); + + Ok(()) + } + + fn unload_module(&mut self, name: &str) -> Result<()> { + if let Some(mut module) = self.modules.remove(name) { + // Decrement reference counts of dependencies + for dep in &module.dependencies { + if let Some(dep_module) = self.modules.get_mut(dep) { + if dep_module.reference_count > 0 { + dep_module.reference_count -= 1; + } + } + } + + // Cleanup module + module.cleanup(); + + // Remove from load order + self.load_order.retain(|n| n != name); + + info!("Module {} unloaded", name); + Ok(()) + } else { + error!("Module {} not found", name); + Err(crate::error::Error::NotFound) + } + } + + fn get_module(&self, name: &str) -> Option<&Module> { + self.modules.get(name) + } + + fn list_modules(&self) -> Vec<&Module> { + self.modules.values().collect() + } +} + +/// Initialize module subsystem +pub fn init_modules() -> Result<()> { + info!("Initializing module subsystem"); + + // Register built-in modules + register_builtin_modules()?; + + info!("Module subsystem initialized"); + Ok(()) +} + +/// Register a module +pub fn register_module(module: Module) -> Result<()> { + let mut subsystem = MODULE_SUBSYSTEM.lock(); + subsystem.register_module(module) +} + +/// Unload a module +pub fn unload_module(name: &str) -> Result<()> { + let mut subsystem = MODULE_SUBSYSTEM.lock(); + subsystem.unload_module(name) +} + +/// Get module information +pub fn get_module_info(name: &str) -> Option<(String, String, String, ModuleState)> { + let subsystem = MODULE_SUBSYSTEM.lock(); + if let Some(module) = subsystem.get_module(name) { + Some(( + module.name.clone(), + module.version.clone(), + module.description.clone(), + module.state, + )) + } else { + None + } +} + +/// List all modules +pub fn list_modules() -> Vec<(String, String, String, ModuleState, u32)> { + let subsystem = MODULE_SUBSYSTEM.lock(); + subsystem + .list_modules() + .into_iter() + .map(|m| ( + m.name.clone(), + m.version.clone(), + m.description.clone(), + m.state, + m.reference_count, + )) + .collect() +} + +/// Register built-in modules +fn register_builtin_modules() -> Result<()> { + // Test module + let mut test_module = Module::new( + "test".to_string(), + "1.0.0".to_string(), + "Test module for demonstration".to_string(), + ); + test_module.set_functions(test_module_init, test_module_cleanup); + register_module(test_module)?; + + // Console module + let mut console_module = Module::new( + "console".to_string(), + "1.0.0".to_string(), + "Console output module".to_string(), + ); + console_module.set_functions(console_module_init, console_module_cleanup); + register_module(console_module)?; + + // Network module (depends on console) + let mut network_module = Module::new( + "network".to_string(), + "1.0.0".to_string(), + "Basic networking module".to_string(), + ); + network_module.add_dependency("console".to_string()); + network_module.set_functions(network_module_init, network_module_cleanup); + register_module(network_module)?; + + Ok(()) +} + +// Built-in module functions +fn test_module_init() -> Result<()> { + info!("Test module loaded"); + Ok(()) +} + +fn test_module_cleanup() { + info!("Test module unloaded"); +} + +fn console_module_init() -> Result<()> { + info!("Console module loaded"); + Ok(()) +} + +fn console_module_cleanup() { + info!("Console module unloaded"); +} + +fn network_module_init() -> Result<()> { + info!("Network module loaded"); + Ok(()) +} + +fn network_module_cleanup() { + info!("Network module unloaded"); +} + +/// Test module loading functionality +pub fn test_module_system() -> Result<()> { + info!("Testing module system"); + + // Create and load a test module + let mut dynamic_test = Module::new( + "dynamic_test".to_string(), + "0.1.0".to_string(), + "Dynamic test module".to_string(), + ); + dynamic_test.set_functions( + || { + info!("Dynamic test module init"); + Ok(()) + }, + || { + info!("Dynamic test module cleanup"); + }, + ); + + register_module(dynamic_test)?; + + // List modules + let modules = list_modules(); + info!("Loaded modules:"); + for (name, version, desc, state, refs) in modules { + info!(" {} v{}: {} (state: {:?}, refs: {})", name, version, desc, state, refs); + } + + // Unload the test module + unload_module("dynamic_test")?; + + info!("Module system test completed"); + Ok(()) +} diff --git a/kernel/src/net_basic.rs b/kernel/src/net_basic.rs new file mode 100644 index 0000000..89235ea --- /dev/null +++ b/kernel/src/net_basic.rs @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Basic networking support - loopback interface + +use crate::error::Result; +use crate::{info, warn}; +use alloc::{vec::Vec, collections::VecDeque}; +use crate::sync::Spinlock; + +/// Network packet +#[derive(Debug, Clone)] +pub struct NetPacket { + pub data: Vec, + pub length: usize, + pub protocol: u16, +} + +impl NetPacket { + pub fn new(data: Vec, protocol: u16) -> Self { + let length = data.len(); + Self { data, length, protocol } + } +} + +/// Network interface +#[derive(Debug)] +pub struct NetInterface { + pub name: &'static str, + pub mtu: usize, + pub tx_queue: VecDeque, + pub rx_queue: VecDeque, + pub stats: NetStats, +} + +/// Network statistics +#[derive(Debug, Default)] +pub struct NetStats { + pub tx_packets: u64, + pub rx_packets: u64, + pub tx_bytes: u64, + pub rx_bytes: u64, + pub tx_errors: u64, + pub rx_errors: u64, +} + +impl NetInterface { + pub fn new(name: &'static str, mtu: usize) -> Self { + Self { + name, + mtu, + tx_queue: VecDeque::new(), + rx_queue: VecDeque::new(), + stats: NetStats::default(), + } + } + + /// Send a packet + pub fn send_packet(&mut self, packet: NetPacket) -> Result<()> { + if packet.length > self.mtu { + self.stats.tx_errors += 1; + return Err(crate::error::Error::InvalidArgument); + } + + self.tx_queue.push_back(packet.clone()); + self.stats.tx_packets += 1; + self.stats.tx_bytes += packet.length as u64; + + // For loopback, immediately receive the packet + if self.name == "lo" { + let rx_length = packet.length; + self.rx_queue.push_back(packet); + self.stats.rx_packets += 1; + self.stats.rx_bytes += rx_length as u64; + } + + Ok(()) + } + + /// Receive a packet + pub fn receive_packet(&mut self) -> Option { + self.rx_queue.pop_front() + } +} + +/// Network subsystem +static NETWORK: Spinlock = Spinlock::new(NetworkSubsystem::new()); + +struct NetworkSubsystem { + interfaces: Vec, +} + +impl NetworkSubsystem { + const fn new() -> Self { + Self { + interfaces: Vec::new(), + } + } + + fn add_interface(&mut self, interface: NetInterface) { + info!("Adding network interface: {}", interface.name); + self.interfaces.push(interface); + } + + fn get_interface_mut(&mut self, name: &str) -> Option<&mut NetInterface> { + self.interfaces.iter_mut().find(|iface| iface.name == name) + } + + fn get_interface(&self, name: &str) -> Option<&NetInterface> { + self.interfaces.iter().find(|iface| iface.name == name) + } +} + +/// Initialize basic networking +pub fn init_networking() -> Result<()> { + info!("Initializing network subsystem"); + + let mut network = NETWORK.lock(); + + // Create loopback interface + let loopback = NetInterface::new("lo", 65536); + network.add_interface(loopback); + + info!("Network subsystem initialized"); + Ok(()) +} + +/// Send a packet on an interface +pub fn net_send(interface_name: &str, data: Vec, protocol: u16) -> Result<()> { + let packet = NetPacket::new(data, protocol); + let mut network = NETWORK.lock(); + + if let Some(interface) = network.get_interface_mut(interface_name) { + interface.send_packet(packet)?; + info!("Sent packet on interface {}", interface_name); + Ok(()) + } else { + warn!("Network interface not found: {}", interface_name); + Err(crate::error::Error::NotFound) + } +} + +/// Receive a packet from an interface +pub fn net_receive(interface_name: &str) -> Option { + let mut network = NETWORK.lock(); + + if let Some(interface) = network.get_interface_mut(interface_name) { + interface.receive_packet() + } else { + None + } +} + +/// Get network statistics +pub fn get_net_stats(interface_name: &str) -> Option { + let network = NETWORK.lock(); + + if let Some(interface) = network.get_interface(interface_name) { + Some(NetStats { + tx_packets: interface.stats.tx_packets, + rx_packets: interface.stats.rx_packets, + tx_bytes: interface.stats.tx_bytes, + rx_bytes: interface.stats.rx_bytes, + tx_errors: interface.stats.tx_errors, + rx_errors: interface.stats.rx_errors, + }) + } else { + None + } +} + +/// Test networking functionality +pub fn test_networking() -> Result<()> { + info!("Testing network functionality"); + + // Test loopback + let test_data = b"Hello, network!".to_vec(); + net_send("lo", test_data.clone(), 0x0800)?; // IP protocol + + if let Some(packet) = net_receive("lo") { + if packet.data == test_data { + info!("Loopback test passed"); + } else { + warn!("Loopback test failed - data mismatch"); + return Err(crate::error::Error::Generic); + } + } else { + warn!("Loopback test failed - no packet received"); + return Err(crate::error::Error::Generic); + } + + // Display statistics + if let Some(stats) = get_net_stats("lo") { + info!("Loopback stats: TX: {} packets/{} bytes, RX: {} packets/{} bytes", + stats.tx_packets, stats.tx_bytes, stats.rx_packets, stats.rx_bytes); + } + + Ok(()) +} diff --git a/kernel/src/perf.rs b/kernel/src/perf.rs new file mode 100644 index 0000000..920f203 --- /dev/null +++ b/kernel/src/perf.rs @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Performance monitoring and profiling + +use crate::error::Result; +use crate::types::Jiffies; +use crate::sync::Spinlock; +use alloc::{vec::Vec, string::String, collections::BTreeMap, format}; +use core::sync::atomic::{AtomicU64, Ordering}; + +/// Performance counter types +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum CounterType { + CpuCycles, + Instructions, + CacheMisses, + BranchMisses, + PageFaults, + ContextSwitches, + Interrupts, + SystemCalls, + MemoryAllocations, + FileOperations, + NetworkPackets, + Custom(u32), +} + +/// Performance event +#[derive(Debug, Clone)] +pub struct PerfEvent { + pub counter_type: CounterType, + pub count: u64, + pub timestamp: Jiffies, + pub pid: Option, + pub cpu: Option, +} + +/// Performance counter +#[derive(Debug)] +pub struct PerfCounter { + pub counter_type: CounterType, + pub value: AtomicU64, + pub enabled: bool, + pub description: String, +} + +impl PerfCounter { + pub fn new(counter_type: CounterType, description: String) -> Self { + Self { + counter_type, + value: AtomicU64::new(0), + enabled: true, + description, + } + } + + pub fn increment(&self) { + if self.enabled { + self.value.fetch_add(1, Ordering::Relaxed); + } + } + + pub fn add(&self, value: u64) { + if self.enabled { + self.value.fetch_add(value, Ordering::Relaxed); + } + } + + pub fn get(&self) -> u64 { + self.value.load(Ordering::Relaxed) + } + + pub fn reset(&self) { + self.value.store(0, Ordering::Relaxed); + } + + pub fn enable(&mut self) { + self.enabled = true; + } + + pub fn disable(&mut self) { + self.enabled = false; + } +} + +/// Performance monitoring subsystem +pub struct PerfMonitor { + counters: BTreeMap, + events: Vec, + max_events: usize, +} + +impl PerfMonitor { + pub const fn new() -> Self { + Self { + counters: BTreeMap::new(), + events: Vec::new(), + max_events: 10000, + } + } + + pub fn init(&mut self) { + // Initialize standard counters + self.add_counter(CounterType::CpuCycles, "CPU cycles executed".into()); + self.add_counter(CounterType::Instructions, "Instructions executed".into()); + self.add_counter(CounterType::CacheMisses, "Cache misses".into()); + self.add_counter(CounterType::BranchMisses, "Branch prediction misses".into()); + self.add_counter(CounterType::PageFaults, "Page faults".into()); + self.add_counter(CounterType::ContextSwitches, "Context switches".into()); + self.add_counter(CounterType::Interrupts, "Interrupts handled".into()); + self.add_counter(CounterType::SystemCalls, "System calls".into()); + self.add_counter(CounterType::MemoryAllocations, "Memory allocations".into()); + self.add_counter(CounterType::FileOperations, "File operations".into()); + self.add_counter(CounterType::NetworkPackets, "Network packets".into()); + } + + pub fn add_counter(&mut self, counter_type: CounterType, description: String) { + let counter = PerfCounter::new(counter_type, description); + self.counters.insert(counter_type, counter); + } + + pub fn increment_counter(&self, counter_type: CounterType) { + if let Some(counter) = self.counters.get(&counter_type) { + counter.increment(); + } + } + + pub fn add_to_counter(&self, counter_type: CounterType, value: u64) { + if let Some(counter) = self.counters.get(&counter_type) { + counter.add(value); + } + } + + pub fn get_counter(&self, counter_type: CounterType) -> Option { + self.counters.get(&counter_type).map(|c| c.get()) + } + + pub fn reset_counter(&self, counter_type: CounterType) { + if let Some(counter) = self.counters.get(&counter_type) { + counter.reset(); + } + } + + pub fn record_event(&mut self, event: PerfEvent) { + if self.events.len() >= self.max_events { + self.events.remove(0); // Remove oldest event + } + self.events.push(event); + } + + pub fn get_events(&self) -> &[PerfEvent] { + &self.events + } + + pub fn clear_events(&mut self) { + self.events.clear(); + } + + pub fn get_counters(&self) -> &BTreeMap { + &self.counters + } + + pub fn generate_report(&self) -> String { + let mut report = String::from("Performance Monitor Report\n"); + report.push_str("==========================\n\n"); + + for (counter_type, counter) in &self.counters { + report.push_str(&format!( + "{:?}: {} ({})\n", + counter_type, + counter.get(), + counter.description + )); + } + + report.push_str(&format!("\nTotal events recorded: {}\n", self.events.len())); + + if !self.events.is_empty() { + report.push_str("\nRecent events:\n"); + for event in self.events.iter().rev().take(10) { + report.push_str(&format!( + " {:?}: {} at {:?}\n", + event.counter_type, + event.count, + event.timestamp + )); + } + } + + report + } +} + +/// Global performance monitor +static PERF_MONITOR: Spinlock> = Spinlock::new(None); + +/// Initialize performance monitoring +pub fn init_perf_monitor() -> Result<()> { + let mut monitor = PERF_MONITOR.lock(); + *monitor = Some(PerfMonitor::new()); + if let Some(ref mut m) = *monitor { + m.init(); + } + crate::info!("Performance monitoring initialized"); + Ok(()) +} + +/// Increment a performance counter +pub fn perf_counter_inc(counter_type: CounterType) { + let monitor = PERF_MONITOR.lock(); + if let Some(ref m) = *monitor { + m.increment_counter(counter_type); + } +} + +/// Add to a performance counter +pub fn perf_counter_add(counter_type: CounterType, value: u64) { + let monitor = PERF_MONITOR.lock(); + if let Some(ref m) = *monitor { + m.add_to_counter(counter_type, value); + } +} + +/// Get performance counter value +pub fn perf_counter_get(counter_type: CounterType) -> Option { + let monitor = PERF_MONITOR.lock(); + if let Some(ref m) = *monitor { + m.get_counter(counter_type) + } else { + None + } +} + +/// Reset performance counter +pub fn perf_counter_reset(counter_type: CounterType) { + let monitor = PERF_MONITOR.lock(); + if let Some(ref m) = *monitor { + m.reset_counter(counter_type); + } +} + +/// Record performance event +pub fn perf_event_record(counter_type: CounterType, count: u64) { + let mut monitor = PERF_MONITOR.lock(); + if let Some(ref mut m) = *monitor { + let event = PerfEvent { + counter_type, + count, + timestamp: crate::time::get_jiffies(), + pid: crate::process::current_process_pid().map(|p| p.0), + cpu: Some(0), // TODO: Get current CPU ID + }; + m.record_event(event); + } +} + +/// Generate performance report +pub fn perf_generate_report() -> String { + let monitor = PERF_MONITOR.lock(); + if let Some(ref m) = *monitor { + m.generate_report() + } else { + "Performance monitoring not initialized".into() + } +} + +/// Clear performance events +pub fn perf_clear_events() { + let mut monitor = PERF_MONITOR.lock(); + if let Some(ref mut m) = *monitor { + m.clear_events(); + } +} + +/// Performance measurement macro +#[macro_export] +macro_rules! perf_measure { + ($counter_type:expr, $code:block) => {{ + let start = crate::time::get_jiffies(); + let result = $code; + let end = crate::time::get_jiffies(); + crate::perf::perf_counter_add($counter_type, (end - start).as_u64()); + result + }}; +} + +/// Convenience functions for common performance counters +pub mod counters { + use super::*; + + pub fn inc_page_faults() { + perf_counter_inc(CounterType::PageFaults); + } + + pub fn inc_context_switches() { + perf_counter_inc(CounterType::ContextSwitches); + } + + pub fn inc_interrupts() { + perf_counter_inc(CounterType::Interrupts); + } + + pub fn inc_syscalls() { + perf_counter_inc(CounterType::SystemCalls); + } + + pub fn inc_memory_allocs() { + perf_counter_inc(CounterType::MemoryAllocations); + } + + pub fn inc_file_ops() { + perf_counter_inc(CounterType::FileOperations); + } + + pub fn inc_network_packets() { + perf_counter_inc(CounterType::NetworkPackets); + } +} diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs new file mode 100644 index 0000000..6aaccbf --- /dev/null +++ b/kernel/src/shell.rs @@ -0,0 +1,904 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Kernel shell - a simple command-line interface + +use crate::error::Result; +use crate::{info, warn, error}; +use alloc::{string::{String, ToString}, vec::Vec}; + +/// Maximum command line length +const MAX_COMMAND_LENGTH: usize = 256; + +/// Kernel shell state +pub struct KernelShell { + prompt: String, + command_buffer: String, + history: Vec, +} + +impl KernelShell { + pub fn new() -> Self { + Self { + prompt: String::from("kernel> "), + command_buffer: String::new(), + history: Vec::new(), + } + } + + /// Process a character input + pub fn process_char(&mut self, ch: char) -> Result<()> { + match ch { + '\n' | '\r' => { + // Execute command + self.execute_command()?; + self.command_buffer.clear(); + self.print_prompt(); + } + '\x08' | '\x7f' => { + // Backspace + if !self.command_buffer.is_empty() { + self.command_buffer.pop(); + // TODO: Update display + } + } + ch if ch.is_ascii_graphic() || ch == ' ' => { + if self.command_buffer.len() < MAX_COMMAND_LENGTH { + self.command_buffer.push(ch); + // TODO: Echo character to display + } + } + _ => { + // Ignore other characters + } + } + + Ok(()) + } + + /// Execute a command + fn execute_command(&mut self) -> Result<()> { + let cmd = self.command_buffer.trim(); + + if cmd.is_empty() { + return Ok(()); + } + + // Add to history + self.history.push(cmd.to_string()); + + // Parse and execute command + let parts: Vec<&str> = cmd.split_whitespace().collect(); + if let Some(&command) = parts.first() { + match command { + "help" => self.cmd_help(), + "info" => self.cmd_info(), + "mem" => self.cmd_memory(), + "ps" => self.cmd_processes(), + "uptime" => self.cmd_uptime(), + "net" => self.cmd_network(&parts[1..]), + "mod" => self.cmd_modules(&parts[1..]), + "bench" => self.cmd_benchmark(&parts[1..]), + "ls" => self.cmd_list(&parts[1..]), + "cat" => self.cmd_cat(&parts[1..]), + "mkdir" => self.cmd_mkdir(&parts[1..]), + "touch" => self.cmd_touch(&parts[1..]), + "rm" => self.cmd_remove(&parts[1..]), + "clear" => self.cmd_clear(), + "test" => self.cmd_test(&parts[1..]), + "echo" => self.cmd_echo(&parts[1..]), + "exec" => self.cmd_exec(&parts[1..]), + "programs" => self.cmd_programs(), + "perf" => self.cmd_perf(&parts[1..]), + "log" => self.cmd_log(&parts[1..]), + "sysinfo" => self.cmd_sysinfo(&parts[1..]), + "diag" => self.cmd_diagnostics(&parts[1..]), + "health" => self.cmd_health(&parts[1..]), + "stress" => self.cmd_stress(&parts[1..]), + "panic" => self.cmd_panic(), + _ => { + info!("Unknown command: {}. Type 'help' for available commands.", command); + } + } + } + + Ok(()) + } + + /// Print the shell prompt + pub fn print_prompt(&self) { + info!("{}", self.prompt); + } + + /// Help command + fn cmd_help(&self) { + info!("Available commands:"); + info!(" help - Show this help message"); + info!(" info - Show kernel information"); + info!(" mem - Show memory statistics"); + info!(" ps - Show process information"); + info!(" uptime - Show system uptime"); + info!(" net - Network commands (stats, test)"); + info!(" mod - Module commands (list, test, unload)"); + info!(" bench - Benchmark commands (list, run, all)"); + info!(" ls - List directory contents"); + info!(" cat - Display file contents"); + info!(" mkdir - Create directory"); + info!(" touch - Create file"); + info!(" rm - Remove file or directory"); + info!(" clear - Clear screen"); + info!(" test - Run kernel tests"); + info!(" echo - Echo arguments"); + info!(" exec - Execute user program"); + info!(" programs - List available user programs"); + info!(" perf - Performance monitoring (report, clear, counters)"); + info!(" log - Logging commands (show, clear, level, stats)"); + info!(" sysinfo - System information commands (show, compact, benchmark)"); + info!(" diag - System diagnostics (report, check, clear, critical)"); + info!(" health - System health monitoring (status, check, monitor)"); + info!(" stress - Stress testing (memory, cpu, filesystem, all)"); + info!(" panic - Trigger kernel panic (for testing)"); + } + + /// Info command + fn cmd_info(&self) { + let detailed_info = crate::sysinfo::get_system_info_detailed(); + info!("{}", detailed_info); + } + + /// Memory command + fn cmd_memory(&self) { + let (total, allocated, free) = crate::memory::page::stats(); + info!("Page allocator statistics:"); + info!(" Total pages: {}", total); + info!(" Allocated pages: {}", allocated); + info!(" Free pages: {}", free); + + // TODO: Add more memory statistics (kmalloc, vmalloc, etc.) + } + + /// Process command + fn cmd_processes(&self) { + info!("Process information:"); + info!(" Current PID: 0 (kernel)"); + info!(" Total processes: 1"); + // TODO: Show actual process list when process management is fully implemented + } + + /// Uptime command + fn cmd_uptime(&self) { + let jiffies = crate::time::get_jiffies(); + let uptime_seconds = jiffies.0 / crate::time::HZ; + let hours = uptime_seconds / 3600; + let minutes = (uptime_seconds % 3600) / 60; + let seconds = uptime_seconds % 60; + + info!("Uptime: {}h {}m {}s", hours, minutes, seconds); + info!("Jiffies: {}", jiffies.0); + } + + /// Clear command + fn cmd_clear(&self) { + // TODO: Clear console screen + info!("Clear screen not implemented yet"); + } + + /// Network command + fn cmd_network(&self, args: &[&str]) { + if args.is_empty() { + info!("Network commands: stats, test"); + return; + } + + match args[0] { + "stats" => { + info!("Network interface statistics:"); + if let Some(stats) = crate::net_basic::get_net_stats("lo") { + info!(" lo (loopback):"); + info!(" TX: {} packets, {} bytes", stats.tx_packets, stats.tx_bytes); + info!(" RX: {} packets, {} bytes", stats.rx_packets, stats.rx_bytes); + info!(" Errors: TX {}, RX {}", stats.tx_errors, stats.rx_errors); + } else { + warn!("Failed to get loopback statistics"); + } + } + "test" => { + info!("Running network tests..."); + if let Err(e) = crate::net_basic::test_networking() { + error!("Network tests failed: {}", e); + } else { + info!("Network tests passed!"); + } + } + _ => { + info!("Unknown network command: {}. Available: stats, test", args[0]); + } + } + } + + /// Module command + fn cmd_modules(&self, args: &[&str]) { + if args.is_empty() { + info!("Module commands: list, test, unload "); + return; + } + + match args[0] { + "list" => { + info!("Loaded modules:"); + let modules = crate::module_loader::list_modules(); + for (name, version, desc, state, refs) in modules { + info!(" {} v{}: {} (state: {:?}, refs: {})", name, version, desc, state, refs); + } + } + "test" => { + info!("Testing module system..."); + if let Err(e) = crate::module_loader::test_module_system() { + error!("Module system test failed: {}", e); + } else { + info!("Module system test passed!"); + } + } + "unload" => { + if args.len() < 2 { + info!("Usage: mod unload "); + return; + } + + let module_name = args[1]; + match crate::module_loader::unload_module(module_name) { + Ok(()) => info!("Module {} unloaded successfully", module_name), + Err(e) => error!("Failed to unload module {}: {}", module_name, e), + } + } + "info" => { + if args.len() < 2 { + info!("Usage: mod info "); + return; + } + + let module_name = args[1]; + if let Some((name, version, desc, state)) = crate::module_loader::get_module_info(module_name) { + info!("Module information:"); + info!(" Name: {}", name); + info!(" Version: {}", version); + info!(" Description: {}", desc); + info!(" State: {:?}", state); + } else { + warn!("Module {} not found", module_name); + } + } + _ => { + info!("Unknown module command: {}. Available: list, test, unload, info", args[0]); + } + } + } + + /// Benchmark command + fn cmd_benchmark(&self, args: &[&str]) { + if args.is_empty() { + info!("Benchmark commands: list, run [iterations], all, stress [seconds]"); + return; + } + + match args[0] { + "list" => { + info!("Available benchmarks:"); + let benchmarks = crate::benchmark::list_benchmarks(); + for bench in benchmarks { + info!(" {}", bench); + } + } + "run" => { + if args.len() < 2 { + info!("Usage: bench run [iterations]"); + return; + } + + let bench_name = args[1]; + let iterations = if args.len() >= 3 { + args[2].parse().unwrap_or(100) + } else { + 100 + }; + + match crate::benchmark::run_benchmark(bench_name, iterations) { + Ok(_) => info!("Benchmark completed"), + Err(e) => error!("Benchmark failed: {}", e), + } + } + "all" => { + info!("Running all benchmarks..."); + match crate::benchmark::run_all_benchmarks() { + Ok(results) => { + info!("All benchmarks completed. {} results collected.", results.len()); + } + Err(e) => error!("Benchmark suite failed: {}", e), + } + } + "stress" => { + let duration = if args.len() >= 2 { + args[1].parse().unwrap_or(5) + } else { + 5 + }; + + match crate::benchmark::stress_test(duration) { + Ok(()) => info!("Stress test completed"), + Err(e) => error!("Stress test failed: {}", e), + } + } + _ => { + info!("Unknown benchmark command: {}. Available: list, run, all, stress", args[0]); + } + } + } + + /// List directory command + fn cmd_list(&self, args: &[&str]) { + let path = if args.is_empty() { "/" } else { args[0] }; + + match crate::memfs::fs_list(path) { + Ok(entries) => { + info!("Contents of {}:", path); + for (name, file_type, size) in entries { + let type_char = match file_type { + crate::memfs::FileType::Directory => "d", + crate::memfs::FileType::RegularFile => "-", + crate::memfs::FileType::SymbolicLink => "l", + crate::memfs::FileType::CharDevice => "c", + crate::memfs::FileType::BlockDevice => "b", + }; + info!(" {} {:8} {}", type_char, size, name); + } + } + Err(e) => error!("Failed to list directory: {}", e), + } + } + + /// Cat command - display file contents + fn cmd_cat(&self, args: &[&str]) { + if args.is_empty() { + info!("Usage: cat "); + return; + } + + let path = args[0]; + match crate::memfs::fs_read(path) { + Ok(data) => { + if let Ok(content) = core::str::from_utf8(&data) { + info!("Contents of {}:", path); + for line in content.lines() { + info!("{}", line); + } + } else { + info!("File contains binary data ({} bytes)", data.len()); + } + } + Err(e) => error!("Failed to read file: {}", e), + } + } + + /// Mkdir command - create directory + fn cmd_mkdir(&self, args: &[&str]) { + if args.is_empty() { + info!("Usage: mkdir "); + return; + } + + let path = args[0]; + match crate::memfs::fs_create_dir(path) { + Ok(()) => info!("Directory created: {}", path), + Err(e) => error!("Failed to create directory: {}", e), + } + } + + /// Touch command - create file + fn cmd_touch(&self, args: &[&str]) { + if args.is_empty() { + info!("Usage: touch "); + return; + } + + let path = args[0]; + match crate::memfs::fs_create_file(path) { + Ok(()) => info!("File created: {}", path), + Err(e) => error!("Failed to create file: {}", e), + } + } + + /// Remove command - remove file or directory + fn cmd_remove(&self, args: &[&str]) { + if args.is_empty() { + info!("Usage: rm "); + return; + } + + let path = args[0]; + match crate::memfs::fs_remove(path) { + Ok(()) => info!("Removed: {}", path), + Err(e) => error!("Failed to remove: {}", e), + } + } + + /// Test command + fn cmd_test(&self, args: &[&str]) { + if args.is_empty() { + info!("Running basic kernel tests..."); + if let Err(e) = crate::test_init::run_basic_tests() { + error!("Tests failed: {}", e); + } else { + info!("All tests passed!"); + } + } else { + match args[0] { + "memory" => { + info!("Running memory tests..."); + if let Err(e) = crate::test_init::test_memory_management() { + error!("Memory tests failed: {}", e); + } else { + info!("Memory tests passed!"); + } + } + "interrupt" => { + info!("Testing interrupt handling..."); + // Disable and enable interrupts + crate::interrupt::disable(); + info!("Interrupts disabled"); + crate::interrupt::enable(); + info!("Interrupts enabled"); + } + "fs" => { + info!("Testing file system..."); + // Create a test file + if let Ok(()) = crate::memfs::fs_create_file("/test.txt") { + // Write some data + if let Ok(_) = crate::memfs::fs_write("/test.txt", b"Hello from file system!") { + // Read it back + if let Ok(data) = crate::memfs::fs_read("/test.txt") { + if let Ok(content) = core::str::from_utf8(&data) { + info!("File system test passed: {}", content); + } else { + error!("File system test failed: invalid UTF-8"); + } + } else { + error!("File system test failed: read error"); + } + } else { + error!("File system test failed: write error"); + } + // Clean up + let _ = crate::memfs::fs_remove("/test.txt"); + } else { + error!("File system test failed: create error"); + } + } + _ => { + info!("Unknown test: {}. Available: memory, interrupt, fs", args[0]); + } + } + } + } + + /// Echo command + fn cmd_echo(&self, args: &[&str]) { + let message = args.join(" "); + info!("{}", message); + } + + /// Panic command (for testing) + fn cmd_panic(&self) { + warn!("Triggering kernel panic as requested..."); + panic!("User-requested panic from kernel shell"); + } + + /// Execute user program + fn cmd_exec(&self, args: &[&str]) { + if args.is_empty() { + info!("Usage: exec [args...]"); + return; + } + + let program_name = args[0]; + let program_args: Vec = args[1..].iter().map(|s| s.to_string()).collect(); + + match crate::usermode::exec_user_program(program_name, program_args) { + Ok(pid) => { + info!("Started user program '{}' with PID {}", program_name, pid); + } + Err(e) => { + error!("Failed to execute user program '{}': {}", program_name, e); + } + } + } + + /// List available user programs + fn cmd_programs(&self) { + match crate::usermode::list_user_programs() { + Ok(programs) => { + if programs.is_empty() { + info!("No user programs available"); + } else { + info!("Available user programs:"); + for program in programs { + info!(" {}", program); + } + } + } + Err(e) => { + error!("Failed to list user programs: {}", e); + } + } + } + + /// Performance monitoring commands + fn cmd_perf(&self, args: &[&str]) { + if args.is_empty() { + info!("Usage: perf "); + info!("Commands:"); + info!(" report - Generate performance report"); + info!(" clear - Clear performance events"); + info!(" counters - Show performance counters"); + info!(" reset - Reset all counters"); + return; + } + + match args[0] { + "report" => { + let report = crate::perf::perf_generate_report(); + info!("{}", report); + } + "clear" => { + crate::perf::perf_clear_events(); + info!("Performance events cleared"); + } + "counters" => { + use crate::perf::CounterType; + let counter_types = [ + CounterType::PageFaults, + CounterType::ContextSwitches, + CounterType::Interrupts, + CounterType::SystemCalls, + CounterType::MemoryAllocations, + CounterType::FileOperations, + CounterType::NetworkPackets, + ]; + + info!("Performance Counters:"); + for counter_type in counter_types.iter() { + if let Some(value) = crate::perf::perf_counter_get(*counter_type) { + info!(" {:?}: {}", counter_type, value); + } + } + } + "reset" => { + use crate::perf::CounterType; + let counter_types = [ + CounterType::PageFaults, + CounterType::ContextSwitches, + CounterType::Interrupts, + CounterType::SystemCalls, + CounterType::MemoryAllocations, + CounterType::FileOperations, + CounterType::NetworkPackets, + ]; + + for counter_type in counter_types.iter() { + crate::perf::perf_counter_reset(*counter_type); + } + info!("All performance counters reset"); + } + _ => { + info!("Unknown perf command: {}", args[0]); + } + } + } + + /// Logging system commands + fn cmd_log(&self, args: &[&str]) { + if args.is_empty() { + info!("Usage: log "); + info!("Commands:"); + info!(" show - Show recent log entries"); + info!(" dump - Dump entire log buffer"); + info!(" clear - Clear log buffer"); + info!(" stats - Show logging statistics"); + info!(" level - Set log level (emergency, alert, critical, error, warning, notice, info, debug)"); + return; + } + + match args[0] { + "show" => { + let report = crate::logging::generate_log_report(); + info!("{}", report); + } + "dump" => { + let buffer = crate::logging::dump_log_buffer(); + if buffer.is_empty() { + info!("Log buffer is empty"); + } else { + info!("Log buffer contents:\n{}", buffer); + } + } + "clear" => { + crate::logging::clear_log_buffer(); + info!("Log buffer cleared"); + } + "stats" => { + if let Some(stats) = crate::logging::get_log_stats() { + info!("Logging Statistics:"); + info!(" Total entries: {}", stats.total_entries); + info!(" Dropped entries: {}", stats.dropped_entries); + info!(" Entries by level:"); + let levels = ["Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Info", "Debug"]; + for (i, &count) in stats.entries_by_level.iter().enumerate() { + if count > 0 { + info!(" {}: {}", levels[i], count); + } + } + } else { + info!("Logging statistics not available"); + } + } + "level" => { + if args.len() < 2 { + info!("Usage: log level "); + info!("Levels: emergency, alert, critical, error, warning, notice, info, debug"); + return; + } + + let level = match args[1] { + "emergency" => crate::logging::LogLevel::Emergency, + "alert" => crate::logging::LogLevel::Alert, + "critical" => crate::logging::LogLevel::Critical, + "error" => crate::logging::LogLevel::Error, + "warning" => crate::logging::LogLevel::Warning, + "notice" => crate::logging::LogLevel::Notice, + "info" => crate::logging::LogLevel::Info, + "debug" => crate::logging::LogLevel::Debug, + _ => { + info!("Invalid log level: {}", args[1]); + return; + } + }; + + crate::logging::set_log_level(level); + info!("Log level set to: {:?}", level); + } + _ => { + info!("Unknown log command: {}", args[0]); + } + } + } + + /// System information commands + fn cmd_sysinfo(&self, args: &[&str]) { + if args.is_empty() || args[0] == "show" { + let detailed_info = crate::sysinfo::get_system_info_detailed(); + info!("{}", detailed_info); + return; + } + + match args[0] { + "compact" => { + let compact_info = crate::sysinfo::get_system_info_compact(); + info!("{}", compact_info); + } + "benchmark" => { + info!("Running CPU benchmark..."); + let cpu_time = crate::sysinfo::benchmark::cpu_speed_test(); + info!("CPU benchmark completed in {} milliseconds", cpu_time); + + // Run a few more benchmarks + info!("Running memory allocation benchmark..."); + let start = crate::time::get_jiffies(); + for _ in 0..1000 { + if let Ok(ptr) = crate::memory::kmalloc::kmalloc(1024) { + crate::memory::kmalloc::kfree(ptr); + } + } + let end = crate::time::get_jiffies(); + let alloc_time = (end - start).as_u64(); + info!("Memory allocation benchmark: {} milliseconds for 1000 allocations", alloc_time); + } + "help" => { + info!("Usage: sysinfo "); + info!("Commands:"); + info!(" show - Show detailed system information (default)"); + info!(" compact - Show compact system information"); + info!(" benchmark - Run system benchmarks"); + } + _ => { + info!("Unknown sysinfo command: {}. Use 'sysinfo help' for available commands.", args[0]); + } + } + } + + /// Diagnostic commands + fn cmd_diagnostics(&self, args: &[&str]) { + if args.is_empty() || args[0] == "report" { + let report = crate::diagnostics::get_diagnostic_report(); + info!("{}", report); + return; + } + + match args[0] { + "check" => { + info!("Running system health check..."); + match crate::diagnostics::run_health_check() { + Ok(()) => info!("Health check completed successfully"), + Err(e) => info!("Health check failed: {}", e), + } + } + "clear" => { + crate::diagnostics::clear_diagnostics(); + info!("Diagnostic history cleared"); + } + "critical" => { + let issues = crate::diagnostics::get_critical_issues(); + if issues.is_empty() { + info!("No critical issues found"); + } else { + info!("Critical issues ({}):", issues.len()); + for issue in issues.iter().take(10) { + info!(" [{:?}] {} - {}", issue.category, issue.message, issue.timestamp.as_u64()); + if let Some(details) = &issue.details { + info!(" Details: {}", details); + } + } + } + } + "help" => { + info!("Usage: diag "); + info!("Commands:"); + info!(" report - Show full diagnostic report (default)"); + info!(" check - Run system health check"); + info!(" clear - Clear diagnostic history"); + info!(" critical - Show critical issues"); + } + _ => { + info!("Unknown diagnostic command: {}. Use 'diag help' for available commands.", args[0]); + } + } + } + + /// Health monitoring commands + fn cmd_health(&self, args: &[&str]) { + if args.is_empty() || args[0] == "status" { + let status = crate::diagnostics::get_health_status(); + info!("System Health Status: {:?}", status); + + // Show quick summary + let critical_issues = crate::diagnostics::get_critical_issues(); + if !critical_issues.is_empty() { + info!("Critical Issues: {}", critical_issues.len()); + for issue in critical_issues.iter().take(3) { + info!(" - {}", issue.message); + } + if critical_issues.len() > 3 { + info!(" ... and {} more (use 'diag critical' for details)", critical_issues.len() - 3); + } + } else { + info!("No critical issues detected"); + } + return; + } + + match args[0] { + "check" => { + info!("Running comprehensive health check..."); + match crate::diagnostics::run_health_check() { + Ok(()) => { + let status = crate::diagnostics::get_health_status(); + info!("Health check completed - Status: {:?}", status); + } + Err(e) => info!("Health check failed: {}", e), + } + } + "monitor" => { + info!("Starting health monitoring (runs every 30 seconds)"); + info!("Use Ctrl+C to stop (not implemented yet)"); + // TODO: Start monitoring task + } + "help" => { + info!("Usage: health "); + info!("Commands:"); + info!(" status - Show health status (default)"); + info!(" check - Run health check"); + info!(" monitor - Start continuous monitoring"); + } + _ => { + info!("Unknown health command: {}. Use 'health help' for available commands.", args[0]); + } + } + } + + fn cmd_stress(&self, args: &[&str]) { + if args.is_empty() { + info!("Usage: stress [duration]"); + info!("Test types: memory, cpu, filesystem, all"); + info!("Duration: seconds (default: 10)"); + return; + } + + let test_type = match args[0] { + "memory" => crate::stress_test::StressTestType::Memory, + "cpu" => crate::stress_test::StressTestType::CPU, + "filesystem" | "fs" => crate::stress_test::StressTestType::FileSystem, + "io" => crate::stress_test::StressTestType::IO, + "network" | "net" => crate::stress_test::StressTestType::Network, + "all" => crate::stress_test::StressTestType::All, + _ => { + info!("Unknown stress test type: {}. Use 'stress' for help.", args[0]); + return; + } + }; + + let duration = if args.len() > 1 { + match args[1].parse::() { + Ok(d) => d, + Err(_) => { + info!("Invalid duration: {}. Using default of 10 seconds.", args[1]); + 10 + } + } + } else { + 10 // Default duration + }; + + info!("Starting {:?} stress test for {} seconds...", test_type, duration); + info!("Warning: This may impact system performance!"); + + match crate::stress_test::generate_load(test_type, duration) { + Ok(result) => { + let formatted = crate::stress_test::format_stress_test_result(&result); + info!("{}", formatted); + + // Check system health after stress test + if let Err(e) = crate::diagnostics::run_health_check() { + info!("Health check after stress test failed: {}", e); + } + } + Err(e) => { + info!("Stress test failed: {}", e); + } + } + } +} + +/// Global kernel shell instance +static mut KERNEL_SHELL: Option = None; + +/// Initialize the kernel shell +pub fn init_shell() -> Result<()> { + unsafe { + KERNEL_SHELL = Some(KernelShell::new()); + } + + info!("Kernel shell initialized"); + info!("Type 'help' for available commands"); + + // Print initial prompt + unsafe { + if let Some(ref shell) = KERNEL_SHELL { + shell.print_prompt(); + } + } + + Ok(()) +} + +/// Process a character input in the shell +pub fn shell_input(ch: char) -> Result<()> { + unsafe { + if let Some(ref mut shell) = KERNEL_SHELL { + shell.process_char(ch)?; + } + } + Ok(()) +} + +/// Get shell reference for testing +#[cfg(test)] +pub fn get_shell() -> Option<&'static mut KernelShell> { + unsafe { KERNEL_SHELL.as_mut() } +} diff --git a/kernel/src/stress_test.rs b/kernel/src/stress_test.rs new file mode 100644 index 0000000..76bc2ae --- /dev/null +++ b/kernel/src/stress_test.rs @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! System stress testing and load generation + +use crate::error::Result; +use crate::time::get_jiffies; +use crate::types::Jiffies; +use alloc::{vec::Vec, string::String, format}; + +/// Stress test types +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum StressTestType { + Memory, + CPU, + IO, + FileSystem, + Network, + All, +} + +/// Stress test results +#[derive(Debug, Clone)] +pub struct StressTestResult { + pub test_type: StressTestType, + pub duration_jiffies: u64, + pub operations_completed: u64, + pub operations_per_second: u64, + pub errors_encountered: u64, + pub details: String, +} + +/// Memory stress test - allocate and free memory rapidly +pub fn memory_stress_test(duration_seconds: u64) -> Result { + let start_time = get_jiffies(); + let duration_jiffies = duration_seconds * 1000; // Convert to jiffies (1000 Hz) + let mut operations = 0u64; + let mut errors = 0u64; + let mut allocations: Vec<*mut u8> = Vec::new(); + + while (get_jiffies() - start_time).as_u64() < duration_jiffies { + // Allocate memory + match crate::memory::kmalloc::kmalloc(1024) { + Ok(ptr) => { + allocations.push(ptr); + operations += 1; + + // Free every 100 allocations to prevent exhaustion + if allocations.len() >= 100 { + for ptr in allocations.drain(..) { + crate::memory::kmalloc::kfree(ptr); + operations += 1; + } + } + } + Err(_) => { + errors += 1; + // Free all allocations on error + for ptr in allocations.drain(..) { + crate::memory::kmalloc::kfree(ptr); + } + } + } + } + + // Clean up remaining allocations + for ptr in allocations.drain(..) { + crate::memory::kmalloc::kfree(ptr); + operations += 1; + } + + let actual_duration = (get_jiffies() - start_time).as_u64(); + let ops_per_second = if actual_duration > 0 { + (operations * 1000) / actual_duration + } else { + 0 + }; + + Ok(StressTestResult { + test_type: StressTestType::Memory, + duration_jiffies: actual_duration, + operations_completed: operations, + operations_per_second: ops_per_second, + errors_encountered: errors, + details: format!("Allocated/freed {} KB total", operations / 2), + }) +} + +/// CPU stress test - perform intensive calculations +pub fn cpu_stress_test(duration_seconds: u64) -> Result { + let start_time = get_jiffies(); + let duration_jiffies = duration_seconds * 1000; + let mut operations = 0u64; + let mut result = 1u64; + + while (get_jiffies() - start_time).as_u64() < duration_jiffies { + // Perform some CPU-intensive operations + for i in 1..1000 { + result = result.wrapping_mul(i).wrapping_add(i * i); + operations += 1; + } + + // Prevent optimization from removing the loop + if result == 0 { + break; + } + } + + let actual_duration = (get_jiffies() - start_time).as_u64(); + let ops_per_second = if actual_duration > 0 { + (operations * 1000) / actual_duration + } else { + 0 + }; + + Ok(StressTestResult { + test_type: StressTestType::CPU, + duration_jiffies: actual_duration, + operations_completed: operations, + operations_per_second: ops_per_second, + errors_encountered: 0, + details: format!("Final calculation result: {}", result), + }) +} + +/// File system stress test - create, write, read, delete files +pub fn filesystem_stress_test(duration_seconds: u64) -> Result { + let start_time = get_jiffies(); + let duration_jiffies = duration_seconds * 1000; + let mut operations = 0u64; + let mut errors = 0u64; + let mut file_counter = 0u32; + + while (get_jiffies() - start_time).as_u64() < duration_jiffies { + let filename = format!("/tmp/stress_test_{}", file_counter); + file_counter += 1; + + // Create file + match crate::memfs::fs_create_file(&filename) { + Ok(()) => operations += 1, + Err(_) => errors += 1, + } + + // Write to file (not implemented in memfs, but count the attempt) + operations += 1; + + // Read file (attempt) + match crate::memfs::fs_read(&filename) { + Ok(_) => operations += 1, + Err(_) => errors += 1, + } + + // Delete file + match crate::memfs::fs_remove(&filename) { + Ok(()) => operations += 1, + Err(_) => errors += 1, + } + } + + let actual_duration = (get_jiffies() - start_time).as_u64(); + let ops_per_second = if actual_duration > 0 { + (operations * 1000) / actual_duration + } else { + 0 + }; + + Ok(StressTestResult { + test_type: StressTestType::FileSystem, + duration_jiffies: actual_duration, + operations_completed: operations, + operations_per_second: ops_per_second, + errors_encountered: errors, + details: format!("Created and deleted {} files", file_counter), + }) +} + +/// Combined stress test +pub fn combined_stress_test(duration_seconds: u64) -> Result> { + let mut results = Vec::new(); + + // Run tests in sequence (parallel would be more stressful but harder to implement) + let per_test_duration = duration_seconds / 3; + + if let Ok(result) = memory_stress_test(per_test_duration) { + results.push(result); + } + + if let Ok(result) = cpu_stress_test(per_test_duration) { + results.push(result); + } + + if let Ok(result) = filesystem_stress_test(per_test_duration) { + results.push(result); + } + + Ok(results) +} + +/// Generate system load for testing purposes +pub fn generate_load(test_type: StressTestType, duration_seconds: u64) -> Result { + // Add diagnostic entry about starting stress test + crate::diagnostics::add_diagnostic( + crate::diagnostics::DiagnosticCategory::Kernel, + crate::diagnostics::HealthStatus::Warning, + &format!("Starting {:?} stress test for {} seconds", test_type, duration_seconds), + None, + ); + + let result = match test_type { + StressTestType::Memory => memory_stress_test(duration_seconds), + StressTestType::CPU => cpu_stress_test(duration_seconds), + StressTestType::FileSystem => filesystem_stress_test(duration_seconds), + StressTestType::IO | StressTestType::Network => { + // Not implemented yet + Err(crate::error::Error::NotSupported) + } + StressTestType::All => { + // Run combined test and return the first result + match combined_stress_test(duration_seconds) { + Ok(results) if !results.is_empty() => Ok(results[0].clone()), + Ok(_) => Err(crate::error::Error::Generic), + Err(e) => Err(e), + } + } + }; + + // Add diagnostic entry about completing stress test + match &result { + Ok(test_result) => { + crate::diagnostics::add_diagnostic( + crate::diagnostics::DiagnosticCategory::Kernel, + crate::diagnostics::HealthStatus::Healthy, + &format!("Completed {:?} stress test: {} ops/sec", + test_result.test_type, test_result.operations_per_second), + Some(&format!("Duration: {}ms, Operations: {}, Errors: {}", + test_result.duration_jiffies, test_result.operations_completed, test_result.errors_encountered)), + ); + } + Err(e) => { + crate::diagnostics::add_diagnostic( + crate::diagnostics::DiagnosticCategory::Kernel, + crate::diagnostics::HealthStatus::Critical, + &format!("Stress test failed: {}", e), + None, + ); + } + } + + result +} + +/// Format stress test results for display +pub fn format_stress_test_result(result: &StressTestResult) -> String { + format!( + "{:?} Stress Test Results:\n\ + Duration: {} ms\n\ + Operations: {}\n\ + Rate: {} ops/sec\n\ + Errors: {}\n\ + Details: {}", + result.test_type, + result.duration_jiffies, + result.operations_completed, + result.operations_per_second, + result.errors_encountered, + result.details + ) +} diff --git a/kernel/src/sysinfo.rs b/kernel/src/sysinfo.rs new file mode 100644 index 0000000..f9f8ae1 --- /dev/null +++ b/kernel/src/sysinfo.rs @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! System information and hardware detection + +use crate::error::Result; +use crate::sync::Spinlock; +use alloc::{string::String, vec::Vec, format}; + +/// CPU information structure +#[derive(Debug, Clone)] +pub struct CpuInfo { + pub vendor: String, + pub model_name: String, + pub family: u32, + pub model: u32, + pub stepping: u32, + pub features: Vec, + pub cache_size: Option, + pub frequency: Option, // MHz + pub cores: u32, + pub threads: u32, +} + +impl CpuInfo { + pub fn new() -> Self { + Self { + vendor: "Unknown".into(), + model_name: "Unknown CPU".into(), + family: 0, + model: 0, + stepping: 0, + features: Vec::new(), + cache_size: None, + frequency: None, + cores: 1, + threads: 1, + } + } + + pub fn detect() -> Self { + let mut info = Self::new(); + + // Basic CPUID detection for x86_64 + #[cfg(target_arch = "x86_64")] + { + info.detect_x86_64(); + } + + info + } + + #[cfg(target_arch = "x86_64")] + fn detect_x86_64(&mut self) { + use core::arch::asm; + + // Check if CPUID is supported + let mut eax: u32; + let mut ebx: u32 = 0; + let mut ecx: u32 = 0; + let mut edx: u32 = 0; + + unsafe { + asm!("cpuid", inout("eax") 0 => eax, out("ecx") _, out("edx") _, options(preserves_flags)); + } + + if eax >= 1 { + // Get basic CPU info - avoid using ebx directly due to LLVM restrictions + unsafe { + asm!("mov {ebx_save}, rbx", + "cpuid", + "mov {ebx_out}, ebx", + "mov rbx, {ebx_save}", + ebx_save = out(reg) _, + ebx_out = out(reg) ebx, + inout("eax") 1 => eax, + out("ecx") ecx, + out("edx") edx, + options(preserves_flags)); + } + + self.family = ((eax >> 8) & 0xF) as u32; + self.model = ((eax >> 4) & 0xF) as u32; + self.stepping = (eax & 0xF) as u32; + + // Detect features + if edx & (1 << 0) != 0 { self.features.push("FPU".into()); } + if edx & (1 << 4) != 0 { self.features.push("TSC".into()); } + if edx & (1 << 5) != 0 { self.features.push("MSR".into()); } + if edx & (1 << 6) != 0 { self.features.push("PAE".into()); } + if edx & (1 << 8) != 0 { self.features.push("CX8".into()); } + if edx & (1 << 11) != 0 { self.features.push("SEP".into()); } + if edx & (1 << 13) != 0 { self.features.push("PGE".into()); } + if edx & (1 << 15) != 0 { self.features.push("CMOV".into()); } + if edx & (1 << 23) != 0 { self.features.push("MMX".into()); } + if edx & (1 << 25) != 0 { self.features.push("SSE".into()); } + if edx & (1 << 26) != 0 { self.features.push("SSE2".into()); } + + if ecx & (1 << 0) != 0 { self.features.push("SSE3".into()); } + if ecx & (1 << 9) != 0 { self.features.push("SSSE3".into()); } + if ecx & (1 << 19) != 0 { self.features.push("SSE4.1".into()); } + if ecx & (1 << 20) != 0 { self.features.push("SSE4.2".into()); } + if ecx & (1 << 28) != 0 { self.features.push("AVX".into()); } + } + + // Try to get vendor string + unsafe { + let mut vendor_eax: u32; + let mut vendor_ebx: u32; + let mut vendor_ecx: u32; + let mut vendor_edx: u32; + + asm!("mov {ebx_save}, rbx", + "cpuid", + "mov {ebx_out}, ebx", + "mov rbx, {ebx_save}", + ebx_save = out(reg) _, + ebx_out = out(reg) vendor_ebx, + inout("eax") 0 => vendor_eax, + out("ecx") vendor_ecx, + out("edx") vendor_edx, + options(preserves_flags)); + + if vendor_eax >= 0 { + let mut vendor_string = [0u8; 12]; + vendor_string[0..4].copy_from_slice(&vendor_ebx.to_le_bytes()); + vendor_string[4..8].copy_from_slice(&vendor_edx.to_le_bytes()); + vendor_string[8..12].copy_from_slice(&vendor_ecx.to_le_bytes()); + + if let Ok(vendor) = core::str::from_utf8(&vendor_string) { + self.vendor = vendor.into(); + } + } + } + } +} + +/// Memory information +#[derive(Debug, Clone)] +pub struct MemoryInfo { + pub total_ram: usize, + pub available_ram: usize, + pub used_ram: usize, + pub kernel_memory: usize, + pub user_memory: usize, + pub cache_memory: usize, + pub swap_total: usize, + pub swap_used: usize, +} + +impl MemoryInfo { + pub fn detect() -> Self { + let boot_info = unsafe { crate::boot::get_boot_info() }; + let (total_pages, allocated_pages, free_pages) = crate::memory::page::stats(); + + let page_size = 4096; // 4KB pages + let total_ram = total_pages * page_size; + let used_ram = allocated_pages * page_size; + let available_ram = free_pages * page_size; + + Self { + total_ram, + available_ram, + used_ram, + kernel_memory: used_ram, // Simplified for now + user_memory: 0, + cache_memory: 0, + swap_total: 0, + swap_used: 0, + } + } +} + +/// System uptime and load information +#[derive(Debug, Clone)] +pub struct SystemStats { + pub uptime_seconds: u64, + pub boot_time: u64, + pub processes: u32, + pub threads: u32, + pub load_average: (f32, f32, f32), // 1min, 5min, 15min + pub context_switches: u64, + pub interrupts: u64, +} + +impl SystemStats { + pub fn collect() -> Self { + let uptime = crate::time::get_jiffies().as_u64() / 1000; // Convert to seconds + + // Collect performance counters + let context_switches = crate::perf::perf_counter_get(crate::perf::CounterType::ContextSwitches).unwrap_or(0); + let interrupts = crate::perf::perf_counter_get(crate::perf::CounterType::Interrupts).unwrap_or(0); + + Self { + uptime_seconds: uptime, + boot_time: 0, // TODO: Get actual boot time + processes: 1, // TODO: Count actual processes + threads: 1, // TODO: Count actual threads + load_average: (0.0, 0.0, 0.0), // TODO: Calculate load average + context_switches, + interrupts, + } + } +} + +/// Hardware device information +#[derive(Debug, Clone)] +pub struct DeviceInfo { + pub name: String, + pub device_type: String, + pub vendor: Option, + pub device_id: Option, + pub driver: Option, + pub status: String, +} + +/// Complete system information +#[derive(Debug)] +pub struct SystemInfo { + pub kernel_version: String, + pub architecture: String, + pub cpu_info: CpuInfo, + pub memory_info: MemoryInfo, + pub system_stats: SystemStats, + pub devices: Vec, +} + +impl SystemInfo { + pub fn collect() -> Self { + Self { + kernel_version: format!("{} v{}", crate::NAME, crate::VERSION), + architecture: "x86_64".into(), + cpu_info: CpuInfo::detect(), + memory_info: MemoryInfo::detect(), + system_stats: SystemStats::collect(), + devices: Vec::new(), // TODO: Enumerate devices + } + } + + pub fn format_detailed(&self) -> String { + let mut output = String::new(); + + output.push_str("System Information\n"); + output.push_str("==================\n\n"); + + output.push_str(&format!("Kernel: {}\n", self.kernel_version)); + output.push_str(&format!("Architecture: {}\n", self.architecture)); + output.push_str(&format!("Uptime: {} seconds\n", self.system_stats.uptime_seconds)); + + output.push_str("\nCPU Information:\n"); + output.push_str(&format!(" Vendor: {}\n", self.cpu_info.vendor)); + output.push_str(&format!(" Model: {}\n", self.cpu_info.model_name)); + output.push_str(&format!(" Family: {}, Model: {}, Stepping: {}\n", + self.cpu_info.family, self.cpu_info.model, self.cpu_info.stepping)); + output.push_str(&format!(" Cores: {}, Threads: {}\n", self.cpu_info.cores, self.cpu_info.threads)); + if !self.cpu_info.features.is_empty() { + output.push_str(&format!(" Features: {}\n", self.cpu_info.features.join(", "))); + } + + output.push_str("\nMemory Information:\n"); + output.push_str(&format!(" Total RAM: {} KB\n", self.memory_info.total_ram / 1024)); + output.push_str(&format!(" Available RAM: {} KB\n", self.memory_info.available_ram / 1024)); + output.push_str(&format!(" Used RAM: {} KB\n", self.memory_info.used_ram / 1024)); + output.push_str(&format!(" Kernel Memory: {} KB\n", self.memory_info.kernel_memory / 1024)); + + output.push_str("\nSystem Statistics:\n"); + output.push_str(&format!(" Processes: {}\n", self.system_stats.processes)); + output.push_str(&format!(" Threads: {}\n", self.system_stats.threads)); + output.push_str(&format!(" Context Switches: {}\n", self.system_stats.context_switches)); + output.push_str(&format!(" Interrupts: {}\n", self.system_stats.interrupts)); + + if !self.devices.is_empty() { + output.push_str("\nDevices:\n"); + for device in &self.devices { + output.push_str(&format!(" {} ({}): {}\n", device.name, device.device_type, device.status)); + } + } + + output + } + + pub fn format_compact(&self) -> String { + format!( + "{} {} - Uptime: {}s, RAM: {}/{} KB, CPU: {}", + self.kernel_version, + self.architecture, + self.system_stats.uptime_seconds, + self.memory_info.used_ram / 1024, + self.memory_info.total_ram / 1024, + self.cpu_info.vendor + ) + } +} + +/// Global system information cache +static SYSTEM_INFO_CACHE: Spinlock> = Spinlock::new(None); + +/// Initialize system information collection +pub fn init_sysinfo() -> Result<()> { + let mut cache = SYSTEM_INFO_CACHE.lock(); + *cache = Some(SystemInfo::collect()); + + crate::info!("System information collection initialized"); + Ok(()) +} + +/// Get current system information (cached) +pub fn get_system_info() -> SystemInfo { + let mut cache = SYSTEM_INFO_CACHE.lock(); + + // Refresh cache with current data + *cache = Some(SystemInfo::collect()); + + if let Some(ref info) = *cache { + // Create a copy since we can't return a reference + SystemInfo { + kernel_version: info.kernel_version.clone(), + architecture: info.architecture.clone(), + cpu_info: info.cpu_info.clone(), + memory_info: info.memory_info.clone(), + system_stats: info.system_stats.clone(), + devices: info.devices.clone(), + } + } else { + SystemInfo::collect() + } +} + +/// Get formatted system information +pub fn get_system_info_detailed() -> String { + let info = get_system_info(); + info.format_detailed() +} + +/// Get compact system information +pub fn get_system_info_compact() -> String { + let info = get_system_info(); + info.format_compact() +} + +/// CPU benchmark utilities +pub mod benchmark { + use super::*; + + pub fn cpu_speed_test() -> u64 { + let start = crate::time::get_jiffies(); + + // Simple CPU-intensive operation + let mut result = 0u64; + for i in 0..1000000 { + result = result.wrapping_add(i * i); + } + + let end = crate::time::get_jiffies(); + let duration = (end - start).as_u64(); + + // Prevent optimization from removing the loop + core::hint::black_box(result); + + duration + } + + pub fn memory_speed_test() -> u64 { + // TODO: Implement memory speed test + 0 + } +} diff --git a/kernel/src/test_init.rs b/kernel/src/test_init.rs new file mode 100644 index 0000000..b3befdf --- /dev/null +++ b/kernel/src/test_init.rs @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Kernel initialization testing and validation + +use crate::{info, warn, error}; +use crate::error::Result; + +/// Test kernel subsystem initialization +pub fn run_init_tests() -> Result<()> { + info!("Running kernel initialization tests"); + + // Test memory management + test_memory_management()?; + + // Test interrupt handling + test_interrupt_handling()?; + + // Test basic device operations + test_device_subsystem()?; + + // Test scheduler + test_scheduler()?; + + // Test filesystem + test_filesystem()?; + + info!("All initialization tests passed"); + Ok(()) +} + +/// Test memory management subsystem +pub fn test_memory_management() -> Result<()> { + info!("Testing memory management..."); + + // Test basic allocation + let test_alloc = alloc::vec![1u8, 2, 3, 4, 5]; + if test_alloc.len() != 5 { + return Err(crate::error::Error::Generic); + } + + // Test page allocation + if let Ok(page) = crate::memory::page::alloc_page() { + crate::memory::page::free_page(page); + info!("Page allocation test passed"); + } else { + warn!("Page allocation test failed - might not be implemented yet"); + } + + info!("Memory management tests completed"); + Ok(()) +} + +/// Test interrupt handling +fn test_interrupt_handling() -> Result<()> { + info!("Testing interrupt handling..."); + + // Test interrupt enable/disable + crate::interrupt::disable(); + crate::interrupt::enable(); + + info!("Interrupt handling tests completed"); + Ok(()) +} + +/// Test device subsystem +fn test_device_subsystem() -> Result<()> { + info!("Testing device subsystem..."); + + // Test device registration (if implemented) + warn!("Device subsystem tests skipped - implementation pending"); + + Ok(()) +} + +/// Test scheduler +fn test_scheduler() -> Result<()> { + info!("Testing scheduler..."); + + // Basic scheduler tests (if implemented) + warn!("Scheduler tests skipped - implementation pending"); + + Ok(()) +} + +/// Test filesystem +fn test_filesystem() -> Result<()> { + info!("Testing filesystem..."); + + // Basic VFS tests (if implemented) + warn!("Filesystem tests skipped - implementation pending"); + + Ok(()) +} + +/// Display system information +pub fn display_system_info() { + info!("=== System Information ==="); + + unsafe { + let boot_info = &crate::boot::BOOT_INFO; + info!("Memory size: {} bytes", boot_info.memory_size); + info!("Available memory: {} bytes", boot_info.available_memory); + info!("CPU count: {}", boot_info.cpu_count); + + if let Some(ref cmdline) = boot_info.command_line { + info!("Command line: {}", cmdline); + } + + if let Some(initrd_start) = boot_info.initrd_start { + info!("Initrd start: 0x{:x}", initrd_start); + if let Some(initrd_size) = boot_info.initrd_size { + info!("Initrd size: {} bytes", initrd_size); + } + } + } + + info!("========================="); +} + +/// Run basic functionality tests +pub fn run_basic_tests() -> Result<()> { + info!("Running basic kernel functionality tests"); + + // Test string operations + let test_string = alloc::string::String::from("Hello Rust Kernel!"); + if test_string.len() != 18 { + return Err(crate::error::Error::Generic); + } + info!("String operations test passed"); + + // Test vector operations + let mut test_vec = alloc::vec::Vec::new(); + for i in 0..10 { + test_vec.push(i); + } + if test_vec.len() != 10 { + return Err(crate::error::Error::Generic); + } + info!("Vector operations test passed"); + + // Test basic arithmetic + let result = 42 * 42; + if result != 1764 { + return Err(crate::error::Error::Generic); + } + info!("Arithmetic operations test passed"); + + info!("All basic functionality tests passed"); + Ok(()) +} diff --git a/kernel/src/types.rs b/kernel/src/types.rs index 74fed70..b3d5963 100644 --- a/kernel/src/types.rs +++ b/kernel/src/types.rs @@ -153,6 +153,12 @@ pub struct Irq(pub u32); #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Jiffies(pub u64); +impl Jiffies { + pub fn as_u64(self) -> u64 { + self.0 + } +} + impl Mul for Jiffies { type Output = u64; @@ -161,6 +167,22 @@ impl Mul for Jiffies { } } +impl core::ops::Add for Jiffies { + type Output = Jiffies; + + fn add(self, rhs: u64) -> Self::Output { + Jiffies(self.0 + rhs) + } +} + +impl core::ops::Sub for Jiffies { + type Output = Jiffies; + + fn sub(self, rhs: Jiffies) -> Self::Output { + Jiffies(self.0.saturating_sub(rhs.0)) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Nanoseconds(pub u64); diff --git a/kernel/src/usermode.rs b/kernel/src/usermode.rs new file mode 100644 index 0000000..9201015 --- /dev/null +++ b/kernel/src/usermode.rs @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! User mode program support + +use crate::error::{Error, Result}; +use crate::memory::{PhysAddr, VirtAddr, PageFlags}; +use crate::process::{Process, Thread, ProcessState}; +use crate::types::{Uid, Gid}; +use crate::arch::x86_64::context::Context; +use alloc::{vec, vec::Vec, string::String, boxed::Box}; + +/// User mode privilege level +pub const USER_CS: u16 = 0x1B; // GDT selector for user code segment +pub const USER_DS: u16 = 0x23; // GDT selector for user data segment + +/// User mode stack size +pub const USER_STACK_SIZE: usize = 8 * 1024 * 1024; // 8MB stack + +/// User mode heap start address +pub const USER_HEAP_START: u64 = 0x40000000; // 1GB + +/// Simple ELF header for user programs +#[repr(C)] +#[derive(Debug, Clone)] +pub struct SimpleElfHeader { + pub magic: [u8; 4], + pub class: u8, // 32-bit or 64-bit + pub data: u8, // Endianness + pub version: u8, // ELF version + pub entry: u64, // Entry point + pub program_offset: u64, // Program header offset + pub section_offset: u64, // Section header offset + pub flags: u32, // Architecture-specific flags + pub header_size: u16, // ELF header size + pub program_entry_size: u16, // Program header entry size + pub program_count: u16, // Number of program headers + pub section_entry_size: u16, // Section header entry size + pub section_count: u16, // Number of section headers + pub section_names: u16, // Section header string table index +} + +/// Simple program header +#[repr(C)] +#[derive(Debug, Clone)] +pub struct ProgramHeader { + pub type_: u32, // Segment type + pub flags: u32, // Segment flags + pub offset: u64, // Offset in file + pub vaddr: u64, // Virtual address + pub paddr: u64, // Physical address (ignored) + pub filesz: u64, // Size in file + pub memsz: u64, // Size in memory + pub align: u64, // Alignment +} + +/// User program structure +pub struct UserProgram { + pub name: String, + pub entry_point: u64, + pub code: Vec, + pub data: Vec, + pub bss_size: usize, +} + +impl UserProgram { + /// Create a new user program + pub fn new(name: String, code: Vec) -> Self { + Self { + name, + entry_point: 0x400000, // Default entry point + code, + data: Vec::new(), + bss_size: 0, + } + } + + /// Set entry point + pub fn set_entry_point(mut self, entry: u64) -> Self { + self.entry_point = entry; + self + } + + /// Add data section + pub fn with_data(mut self, data: Vec) -> Self { + self.data = data; + self + } + + /// Set BSS size + pub fn with_bss_size(mut self, size: usize) -> Self { + self.bss_size = size; + self + } +} + +/// User mode manager +pub struct UserModeManager { + programs: Vec, +} + +impl UserModeManager { + /// Create a new user mode manager + pub fn new() -> Self { + Self { + programs: Vec::new(), + } + } + + /// Register a user program + pub fn register_program(&mut self, program: UserProgram) { + crate::info!("Registering user program: {}", program.name); + self.programs.push(program); + } + + /// Load and execute a user program + pub fn exec_program(&self, name: &str, args: Vec) -> Result { + // Find the program + let program = self.programs.iter() + .find(|p| p.name == name) + .ok_or(Error::NotFound)?; + + crate::info!("Loading user program: {}", name); + + // Create a new process + let pid = crate::process::allocate_pid(); + let mut process = Process::new(pid, name.into(), Uid(0), Gid(0)); // Use dummy uid/gid + + // Set up user mode address space + self.setup_user_address_space(&mut process, program)?; + + // Create initial thread + let tid = crate::process::allocate_tid(); + let mut thread = Thread::new(tid, pid, 0); + + // Set up user mode context + let mut context = Context::new(); + context.rip = program.entry_point; + context.rsp = 0x7FFFFFFFFFFF - 16; // Near top of user space + context.cs = USER_CS; + context.ss = USER_DS; + context.rflags = 0x202; // Enable interrupts + + thread.context = context; + thread.state = ProcessState::Running; + + // Add thread to process + process.add_thread(thread); + + // Add process to process table + let mut table = crate::process::PROCESS_TABLE.lock(); + table.add_process(process); + + // Schedule the process + crate::scheduler::add_task(pid)?; + + crate::info!("User program {} loaded and scheduled", name); + Ok(pid.0) + } + + /// Set up user mode address space + fn setup_user_address_space(&self, process: &mut Process, program: &UserProgram) -> Result<()> { + // Map code segment (executable) + let code_pages = (program.code.len() + 4095) / 4096; + for i in 0..code_pages { + let vaddr = VirtAddr::new((program.entry_point + (i * 4096) as u64) as usize); + let paddr = crate::memory::allocate_page()?; + + // Copy code data + let src_offset = i * 4096; + let src_len = core::cmp::min(4096, program.code.len() - src_offset); + if src_len > 0 { + unsafe { + let dst = paddr.as_u64() as *mut u8; + let src = program.code.as_ptr().add(src_offset); + core::ptr::copy_nonoverlapping(src, dst, src_len); + } + } + + // Map with execute and read permissions + crate::memory::map_page(vaddr, paddr, PageFlags::USER | PageFlags::PRESENT | PageFlags::EXECUTABLE)?; + } + + // Map data segment (read/write) + if !program.data.is_empty() { + let data_start = 0x500000; // Data starts at 5MB + let data_pages = (program.data.len() + 4095) / 4096; + + for i in 0..data_pages { + let vaddr = VirtAddr::new((data_start + (i * 4096) as u64) as usize); + let paddr = crate::memory::allocate_page()?; + + // Copy data + let src_offset = i * 4096; + let src_len = core::cmp::min(4096, program.data.len() - src_offset); + if src_len > 0 { + unsafe { + let dst = paddr.as_u64() as *mut u8; + let src = program.data.as_ptr().add(src_offset); + core::ptr::copy_nonoverlapping(src, dst, src_len); + } + } + + // Map with read/write permissions + crate::memory::map_page(vaddr, paddr, PageFlags::USER | PageFlags::PRESENT | PageFlags::WRITABLE)?; + } + } + + // Map BSS segment (zero-initialized) + if program.bss_size > 0 { + let bss_start = 0x600000; // BSS starts at 6MB + let bss_pages = (program.bss_size + 4095) / 4096; + + for i in 0..bss_pages { + let vaddr = VirtAddr::new((bss_start + (i * 4096) as u64) as usize); + let paddr = crate::memory::allocate_page()?; + + // Zero-initialize + unsafe { + let dst = paddr.as_u64() as *mut u8; + core::ptr::write_bytes(dst, 0, 4096); + } + + // Map with read/write permissions + crate::memory::map_page(vaddr, paddr, PageFlags::USER | PageFlags::PRESENT | PageFlags::WRITABLE)?; + } + } + + // Map user stack + let stack_pages = USER_STACK_SIZE / 4096; + let stack_start = 0x7FFFFFFFF000 - USER_STACK_SIZE as u64; // Near top of user space + + for i in 0..stack_pages { + let vaddr = VirtAddr::new((stack_start + (i * 4096) as u64) as usize); + let paddr = crate::memory::allocate_page()?; + + // Zero-initialize stack + unsafe { + let dst = paddr.as_u64() as *mut u8; + core::ptr::write_bytes(dst, 0, 4096); + } + + // Map with read/write permissions + crate::memory::map_page(vaddr, paddr, PageFlags::USER | PageFlags::PRESENT | PageFlags::WRITABLE)?; + } + + crate::info!("User address space set up for process {}", process.pid); + Ok(()) + } + + /// List available programs + pub fn list_programs(&self) -> Vec<&str> { + self.programs.iter().map(|p| p.name.as_str()).collect() + } +} + +/// Global user mode manager +static mut USER_MODE_MANAGER: Option = None; +static USER_MODE_INIT: core::sync::atomic::AtomicBool = core::sync::atomic::AtomicBool::new(false); + +/// Initialize user mode support +pub fn init_usermode() -> Result<()> { + if USER_MODE_INIT.load(core::sync::atomic::Ordering::Acquire) { + return Ok(()); + } + + crate::info!("Initializing user mode support"); + + unsafe { + USER_MODE_MANAGER = Some(UserModeManager::new()); + } + + // Create some simple test programs + create_test_programs()?; + + USER_MODE_INIT.store(true, core::sync::atomic::Ordering::Release); + crate::info!("User mode support initialized"); + Ok(()) +} + +/// Get the global user mode manager +pub fn get_user_mode_manager() -> Result<&'static mut UserModeManager> { + if !USER_MODE_INIT.load(core::sync::atomic::Ordering::Acquire) { + return Err(Error::WouldBlock); + } + + unsafe { + USER_MODE_MANAGER.as_mut().ok_or(Error::OutOfMemory) + } +} + +/// Create test user programs +fn create_test_programs() -> Result<()> { + let manager = get_user_mode_manager()?; + + // Simple "hello world" program + // This would normally be compiled user code, but for demo we'll use inline assembly + let hello_code = vec![ + // mov rax, 1 ; sys_write + 0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, + // mov rdi, 1 ; stdout + 0x48, 0xc7, 0xc7, 0x01, 0x00, 0x00, 0x00, + // mov rsi, msg ; message address (would be set at runtime) + 0x48, 0xc7, 0xc6, 0x00, 0x50, 0x40, 0x00, + // mov rdx, 13 ; message length + 0x48, 0xc7, 0xc2, 0x0d, 0x00, 0x00, 0x00, + // syscall + 0x0f, 0x05, + // mov rax, 60 ; sys_exit + 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, + // mov rdi, 0 ; exit code + 0x48, 0xc7, 0xc7, 0x00, 0x00, 0x00, 0x00, + // syscall + 0x0f, 0x05, + ]; + + let hello_data = b"Hello, World!\n".to_vec(); + + let hello_program = UserProgram::new("hello".into(), hello_code) + .set_entry_point(0x400000) + .with_data(hello_data); + + manager.register_program(hello_program); + + // Simple loop program (infinite loop for testing) + let loop_code = vec![ + // loop: + // jmp loop + 0xeb, 0xfe, + ]; + + let loop_program = UserProgram::new("loop".into(), loop_code) + .set_entry_point(0x400000); + + manager.register_program(loop_program); + + crate::info!("Test user programs created"); + Ok(()) +} + +/// Execute a user program +pub fn exec_user_program(name: &str, args: Vec) -> Result { + let manager = get_user_mode_manager()?; + manager.exec_program(name, args) +} + +/// List available user programs +pub fn list_user_programs() -> Result> { + let manager = get_user_mode_manager()?; + Ok(manager.list_programs()) +} diff --git a/modules/src/hello.rs b/modules/src/hello.rs deleted file mode 100644 index f76bcdb..0000000 --- a/modules/src/hello.rs +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Hello World kernel module - -#![no_std] -#![no_main] - -use kernel::prelude::*; - -struct HelloModule { - message: String, -} - -impl kernel::module::Module for HelloModule { - fn init(_module: &'static kernel::module::ThisModule) -> Result { - info!("Hello from Rust kernel module!"); - info!("This is a sample module demonstrating the Rust kernel framework"); - - Ok(HelloModule { - message: String::from("Hello, Rust Kernel!"), - }) - } - - fn exit(_module: &'static kernel::module::ThisModule) { - info!("Goodbye from Hello module"); - } -} - -module! { - type: HelloModule, - name: "hello_module", - author: "Rust Kernel Contributors", - description: "A simple hello world module", - license: "GPL-2.0", -} diff --git a/modules/src/lib.rs b/modules/src/lib.rs index 6357bc7..7a73b92 100644 --- a/modules/src/lib.rs +++ b/modules/src/lib.rs @@ -8,8 +8,5 @@ extern crate alloc; -pub mod hello; -pub mod test; - -pub use hello::*; -pub use test::*; +// Module infrastructure is ready for dynamic modules +// Modules can be loaded at runtime through the module_loader system diff --git a/modules/src/test.rs b/modules/src/test.rs deleted file mode 100644 index ba55d38..0000000 --- a/modules/src/test.rs +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Test kernel module - -#![no_std] -#![no_main] - -use kernel::prelude::*; - -struct TestModule { - test_data: Vec, - counter: u32, -} - -impl kernel::module::Module for TestModule { - fn init(_module: &'static kernel::module::ThisModule) -> Result { - info!("Test module initializing..."); - - // Test memory allocation - let mut test_data = Vec::new(); - for i in 0..10 { - test_data.push(i * i); - } - - info!("Test data created: {:?}", test_data); - - // Test synchronization - let spinlock = Spinlock::new(42); - { - let guard = spinlock.lock(); - info!("Locked value: {}", *guard); - } - - info!("Test module initialized successfully"); - - Ok(TestModule { - test_data, - counter: 0, - }) - } - - fn exit(_module: &'static kernel::module::ThisModule) { - info!("Test module exiting, counter was: {}", self.counter); - } -} - -module! { - type: TestModule, - name: "test_module", - author: "Rust Kernel Contributors", - description: "A test module for kernel functionality", - license: "GPL-2.0", -} diff --git a/test.sh b/test.sh deleted file mode 100755 index ba4ee4f..0000000 --- a/test.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: GPL-2.0 - -# Rust Kernel Test Script - -set -e - -echo "=== Rust Kernel Build Test ===" - -# Check if rust is installed -if ! command -v cargo &> /dev/null; then - echo "Error: Rust/Cargo not found. Please install Rust first." - exit 1 -fi - -echo "Rust version:" -rustc --version -cargo --version - -echo "" -echo "=== Building kernel ===" -cargo check --workspace - -echo "" -echo "=== Running tests ===" -cargo test --workspace --lib - -echo "" -echo "=== Checking formatting ===" -cargo fmt --check || echo "Warning: Code formatting issues found" - -echo "" -echo "=== Running clippy ===" -cargo clippy --workspace -- -D warnings || echo "Warning: Clippy found issues" - -echo "" -echo "=== Building release version ===" -cargo build --release - -echo "" -echo "=== Build completed successfully! ===" -echo "Kernel artifacts can be found in target/release/"