Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2025-06-19 07:04:26 +02:00
padre da14be0d9a
commit 6f01dd44e3
Se han modificado 45 ficheros con 6613 adiciones y 885 borrados

Ver fichero

@@ -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.

Ver fichero

@@ -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"

Ver fichero

@@ -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

197
README.md
Ver fichero

@@ -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 <type> [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 <file>` - Display file contents
- `mkdir <path>` - Create directory
- `touch <file>` - Create file
- `rm <path>` - Remove file/directory
### Development
- `test [all|memory|fs|module]` - Run kernel tests
- `mod [list|test|unload]` - Module management
- `exec <program>` - 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

Ver fichero

@@ -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<usize> {
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<usize> {
info!("DummyDriver: write at offset {} for {} bytes", offset, buffer.len());
Ok(buffer.len())
}
fn ioctl(&self, cmd: u32, arg: usize) -> Result<usize> {
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<Self> {
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",
}

Ver fichero

@@ -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::*;

Ver fichero

@@ -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::<ExampleDeviceData>() {
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<Self> {
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",
}

6
kernel/.cargo/config.toml Archivo normal
Ver fichero

@@ -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",
]

Ver fichero

@@ -21,3 +21,8 @@ default = []
alloc = []
smp = [] # Symmetric Multi-Processing
debug = []
[build-dependencies]
cc = "1.0"
# Profile configuration moved to workspace root

11
kernel/build.rs Archivo normal
Ver fichero

@@ -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");
}

39
kernel/linker.ld Archivo normal
Ver fichero

@@ -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 = .;
}

274
kernel/src/arch/x86_64/boot.s Archivo normal
Ver fichero

@@ -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"

Ver fichero

@@ -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

Ver fichero

@@ -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

Ver fichero

@@ -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)
);
}
}

Ver fichero

@@ -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");
}

Ver fichero

@@ -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)
);
}

188
kernel/src/benchmark.rs Archivo normal
Ver fichero

@@ -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, &times);
result.print();
result
}
/// Memory allocation benchmark
fn bench_memory_alloc() {
let _vec: Vec<u8> = Vec::with_capacity(1024);
}
/// Memory deallocation benchmark
fn bench_memory_dealloc() {
let vec: Vec<u8> = 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<Vec<BenchmarkResult>> {
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<BenchmarkResult> {
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(())
}

Ver fichero

@@ -29,6 +29,7 @@ pub struct BootInfo {
pub command_line: Option<alloc::string::String>,
pub initrd_start: Option<usize>,
pub initrd_size: Option<usize>,
pub multiboot_addr: Option<usize>,
}
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: 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<MemoryMapEntry>,
}
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");
}

221
kernel/src/boot_clean.rs Archivo normal
Ver fichero

@@ -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<alloc::string::String>,
pub initrd_start: Option<usize>,
pub initrd_size: Option<usize>,
pub multiboot_addr: Option<usize>,
}
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: 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<MemoryMapEntry>,
}
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(())
}

Ver fichero

@@ -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<'_> {

289
kernel/src/diagnostics.rs Archivo normal
Ver fichero

@@ -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<String>,
}
/// System diagnostics
pub struct SystemDiagnostics {
entries: Vec<DiagnosticEntry>,
last_check: Jiffies,
health_status: HealthStatus,
}
static DIAGNOSTICS: Spinlock<SystemDiagnostics> = 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<DiagnosticEntry> {
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);
}
}

134
kernel/src/drivers_init.rs Archivo normal
Ver fichero

@@ -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
];

Ver fichero

@@ -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();

Ver fichero

@@ -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::<Idt>() - 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));
}
}

192
kernel/src/kthread.rs Archivo normal
Ver fichero

@@ -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<KthreadManager> = Spinlock::new(KthreadManager::new());
static NEXT_KTHREAD_ID: AtomicU32 = AtomicU32::new(1);
/// Kernel thread manager
struct KthreadManager {
threads: Vec<Kthread>,
}
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<KthreadId> {
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<usize> {
let manager = KTHREAD_MANAGER.lock();
Ok(manager.threads.len())
}

Ver fichero

@@ -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()]) {

457
kernel/src/logging.rs Archivo normal
Ver fichero

@@ -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<u32>,
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<DebugCategory>,
}
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<LogEntry>,
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<Option<KernelLogger>> = 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<LogStats> {
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");
}
}

477
kernel/src/memfs.rs Archivo normal
Ver fichero

@@ -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<u8>,
pub children: BTreeMap<String, Box<MemFile>>,
pub parent: Option<String>,
}
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<usize> {
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<usize> {
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<usize> {
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<usize> {
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<Vec<(String, FileType, usize)>> {
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<Option<MemFileSystem>> = 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<Vec<(String, FileType, usize)>> {
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<Vec<u8>> {
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<usize> {
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<FileSystemStats> {
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)
}
}

Ver fichero

@@ -93,6 +93,9 @@ static SLAB_ALLOCATOR: Spinlock<SlabAllocator> = 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);
}

Ver fichero

@@ -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<MemoryStats> {
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<PhysAddr> {
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<PhysAddr> {
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

Ver fichero

@@ -93,17 +93,17 @@ pub mod page_flags {
}
/// Page frame allocator
static PAGE_ALLOCATOR: Spinlock<PageAllocator> = Spinlock::new(PageAllocator::new());
pub static PAGE_ALLOCATOR: Spinlock<PageAllocator> = Spinlock::new(PageAllocator::new());
/// Page allocator implementation
struct PageAllocator {
pub struct PageAllocator {
free_pages: BTreeSet<Pfn>,
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<PhysAddr> {
let mut allocator = PAGE_ALLOCATOR.lock();
@@ -164,6 +180,11 @@ pub fn alloc_page() -> Result<PhysAddr> {
Ok(pfn.to_phys_addr())
}
/// Allocate a page of physical memory (alias for alloc_page)
pub fn allocate_page() -> Result<PhysAddr> {
alloc_page()
}
/// Free a page of physical memory
pub fn free_page(addr: PhysAddr) {
let pfn = Pfn::from_phys_addr(addr);

314
kernel/src/module_loader.rs Archivo normal
Ver fichero

@@ -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<fn() -> Result<()>>,
pub cleanup_fn: Option<fn()>,
pub reference_count: u32,
pub dependencies: Vec<String>,
}
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<ModuleSubsystem> = Spinlock::new(ModuleSubsystem::new());
struct ModuleSubsystem {
modules: BTreeMap<String, Module>,
load_order: Vec<String>,
}
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(())
}

198
kernel/src/net_basic.rs Archivo normal
Ver fichero

@@ -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<u8>,
pub length: usize,
pub protocol: u16,
}
impl NetPacket {
pub fn new(data: Vec<u8>, 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<NetPacket>,
pub rx_queue: VecDeque<NetPacket>,
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<NetPacket> {
self.rx_queue.pop_front()
}
}
/// Network subsystem
static NETWORK: Spinlock<NetworkSubsystem> = Spinlock::new(NetworkSubsystem::new());
struct NetworkSubsystem {
interfaces: Vec<NetInterface>,
}
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<u8>, 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<NetPacket> {
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<NetStats> {
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(())
}

318
kernel/src/perf.rs Archivo normal
Ver fichero

@@ -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<u32>,
pub cpu: Option<u32>,
}
/// 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<CounterType, PerfCounter>,
events: Vec<PerfEvent>,
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<u64> {
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<CounterType, PerfCounter> {
&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<Option<PerfMonitor>> = 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<u64> {
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);
}
}

904
kernel/src/shell.rs Archivo normal
Ver fichero

@@ -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<String>,
}
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 <name>");
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 <module_name>");
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 <module_name>");
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 <name> [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 <benchmark_name> [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 <filename>");
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 <directory_name>");
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 <filename>");
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 <path>");
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 <program_name> [args...]");
return;
}
let program_name = args[0];
let program_args: Vec<String> = 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 <command>");
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 <command>");
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 <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 <command>");
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 <command>");
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 <command>");
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 <test_type> [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::<u64>() {
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<KernelShell> = 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() }
}

267
kernel/src/stress_test.rs Archivo normal
Ver fichero

@@ -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<StressTestResult> {
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<StressTestResult> {
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<StressTestResult> {
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<Vec<StressTestResult>> {
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<StressTestResult> {
// 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
)
}

366
kernel/src/sysinfo.rs Archivo normal
Ver fichero

@@ -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<String>,
pub cache_size: Option<usize>,
pub frequency: Option<u64>, // 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<String>,
pub device_id: Option<u32>,
pub driver: Option<String>,
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<DeviceInfo>,
}
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<Option<SystemInfo>> = 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
}
}

150
kernel/src/test_init.rs Archivo normal
Ver fichero

@@ -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(())
}

Ver fichero

@@ -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<u64> for Jiffies {
type Output = u64;
@@ -161,6 +167,22 @@ impl Mul<u64> for Jiffies {
}
}
impl core::ops::Add<u64> for Jiffies {
type Output = Jiffies;
fn add(self, rhs: u64) -> Self::Output {
Jiffies(self.0 + rhs)
}
}
impl core::ops::Sub<Jiffies> 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);

350
kernel/src/usermode.rs Archivo normal
Ver fichero

@@ -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<u8>,
pub data: Vec<u8>,
pub bss_size: usize,
}
impl UserProgram {
/// Create a new user program
pub fn new(name: String, code: Vec<u8>) -> 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<u8>) -> 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<UserProgram>,
}
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<String>) -> Result<u32> {
// 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<UserModeManager> = 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<String>) -> Result<u32> {
let manager = get_user_mode_manager()?;
manager.exec_program(name, args)
}
/// List available user programs
pub fn list_user_programs() -> Result<Vec<&'static str>> {
let manager = get_user_mode_manager()?;
Ok(manager.list_programs())
}

Ver fichero

@@ -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<Self> {
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",
}

Ver fichero

@@ -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

Ver fichero

@@ -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<u32>,
counter: u32,
}
impl kernel::module::Module for TestModule {
fn init(_module: &'static kernel::module::ThisModule) -> Result<Self> {
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",
}

42
test.sh
Ver fichero

@@ -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/"