125
ARCHITECTURE.md
125
ARCHITECTURE.md
@@ -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.
|
|
||||||
14
Cargo.toml
14
Cargo.toml
@@ -9,7 +9,7 @@ license = "GPL-2.0"
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"kernel",
|
"kernel",
|
||||||
"drivers",
|
"drivers",
|
||||||
"modules"
|
"modules"
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -19,20 +19,12 @@ kernel = { path = "kernel" }
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
kernel = { path = "kernel" }
|
kernel = { path = "kernel" }
|
||||||
|
|
||||||
[lib]
|
# Workspace-level profile configuration
|
||||||
name = "rust_kernel"
|
|
||||||
crate-type = ["staticlib", "cdylib"]
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["alloc", "std"]
|
|
||||||
alloc = []
|
|
||||||
std = []
|
|
||||||
no_std = []
|
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
opt-level = 0
|
opt-level = 0
|
||||||
debug = true
|
debug = true
|
||||||
|
lto = false
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -66,8 +66,13 @@ clippy:
|
|||||||
doc:
|
doc:
|
||||||
$(CARGO) doc $(CARGO_FLAGS) --no-deps
|
$(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 (placeholder)
|
||||||
install:
|
install:
|
||||||
@echo "Install target not implemented yet"
|
@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
197
README.md
@@ -1,53 +1,168 @@
|
|||||||
# Rust Kernel
|
# 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
|
## Features
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
### Core Systems
|
### Core Systems
|
||||||
- `lib.rs` - Main kernel entry point and module declarations
|
- **Memory Management**: Page allocation, kmalloc/vmalloc, physical/virtual memory mapping
|
||||||
- `prelude.rs` - Common imports and essential types
|
- **Process Management**: Basic process structures, kernel threads, scheduling framework
|
||||||
- `error.rs` - Kernel error types and errno mappings
|
- **File System**: In-memory file system (memfs) with shell integration
|
||||||
- `types.rs` - Fundamental kernel data types (PIDs, UIDs, device IDs, etc.)
|
- **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/`)
|
### Advanced Features
|
||||||
- `page.rs` - Physical page frame allocation and management
|
- **System Diagnostics**: Real-time health monitoring with categorized diagnostics
|
||||||
- `allocator.rs` - High-level memory allocation interfaces
|
- **Performance Monitoring**: Comprehensive performance counters and analysis
|
||||||
- `kmalloc.rs` - Kernel memory allocation (slab allocator)
|
- **Stress Testing**: Memory, CPU, and filesystem stress testing with metrics
|
||||||
- `vmalloc.rs` - Virtual memory allocation and VMA tracking
|
- **Advanced Logging**: Multi-level logging with filtering and statistics
|
||||||
- `page_table.rs` - Page table management and virtual memory mapping
|
- **System Information**: Detailed hardware detection and system reporting
|
||||||
|
- **Interactive Shell**: 20+ commands for system administration and testing
|
||||||
|
|
||||||
### Process Management
|
### Architecture Support
|
||||||
- `process.rs` - Process and thread structures, fork/exec/wait/exit
|
- **x86_64**: Complete support with GDT, IDT, paging, and exception handling
|
||||||
- `scheduler.rs` - Process scheduling and task switching
|
- **Boot Process**: Multiboot-compatible with staged initialization
|
||||||
- `task.rs` - Task management and process lists
|
- **Hardware Detection**: CPUID-based CPU information and feature detection
|
||||||
|
|
||||||
### File System (`fs/`)
|
## Quick Start
|
||||||
- `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
|
|
||||||
|
|
||||||
### 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.rs` - Basic device abstraction
|
||||||
- `device_advanced.rs` - Advanced device driver framework with power management
|
- `device_advanced.rs` - Advanced device driver framework with power management
|
||||||
- `driver.rs` - Device driver registration and management
|
- `driver.rs` - Device driver registration and management
|
||||||
|
|||||||
@@ -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",
|
|
||||||
}
|
|
||||||
@@ -8,14 +8,8 @@
|
|||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
pub mod dummy;
|
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
pub mod platform_example;
|
|
||||||
pub mod ramdisk;
|
pub mod ramdisk;
|
||||||
pub mod keyboard; // New keyboard driver
|
pub mod keyboard; // Keyboard driver
|
||||||
pub mod serial; // New serial driver
|
pub mod serial; // Serial driver
|
||||||
|
|
||||||
pub use dummy::*;
|
|
||||||
pub use mem::*;
|
|
||||||
pub use platform_example::*;
|
|
||||||
pub use ramdisk::*;
|
pub use ramdisk::*;
|
||||||
|
|||||||
@@ -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
6
kernel/.cargo/config.toml
Archivo normal
@@ -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",
|
||||||
|
]
|
||||||
@@ -21,3 +21,8 @@ default = []
|
|||||||
alloc = []
|
alloc = []
|
||||||
smp = [] # Symmetric Multi-Processing
|
smp = [] # Symmetric Multi-Processing
|
||||||
debug = []
|
debug = []
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = "1.0"
|
||||||
|
|
||||||
|
# Profile configuration moved to workspace root
|
||||||
|
|||||||
11
kernel/build.rs
Archivo normal
11
kernel/build.rs
Archivo normal
@@ -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
39
kernel/linker.ld
Archivo normal
@@ -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
274
kernel/src/arch/x86_64/boot.s
Archivo normal
@@ -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"
|
||||||
44
kernel/src/arch/x86_64/boot_entry.s
Archivo normal
44
kernel/src/arch/x86_64/boot_entry.s
Archivo normal
@@ -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
|
||||||
114
kernel/src/arch/x86_64/exceptions.s
Archivo normal
114
kernel/src/arch/x86_64/exceptions.s
Archivo normal
@@ -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
|
||||||
@@ -1,4 +1,152 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
//! GDT stub
|
//! Global Descriptor Table (GDT) for x86_64
|
||||||
pub fn init() {}
|
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,492 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
//! IDT stub
|
//! Interrupt Descriptor Table (IDT) for x86_64
|
||||||
pub fn init() {}
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,3 +30,25 @@ impl Port {
|
|||||||
value
|
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
188
kernel/src/benchmark.rs
Archivo normal
@@ -0,0 +1,188 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
//! Kernel benchmark system
|
||||||
|
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::{info, warn};
|
||||||
|
use crate::time::{get_jiffies, monotonic_time, TimeSpec};
|
||||||
|
use alloc::{vec, vec::Vec, string::{String, ToString}};
|
||||||
|
|
||||||
|
/// Benchmark result
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct BenchmarkResult {
|
||||||
|
pub name: String,
|
||||||
|
pub iterations: u64,
|
||||||
|
pub total_time_ns: u64,
|
||||||
|
pub avg_time_ns: u64,
|
||||||
|
pub min_time_ns: u64,
|
||||||
|
pub max_time_ns: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BenchmarkResult {
|
||||||
|
pub fn new(name: String, iterations: u64, times: &[u64]) -> Self {
|
||||||
|
let total_time_ns = times.iter().sum();
|
||||||
|
let avg_time_ns = total_time_ns / iterations;
|
||||||
|
let min_time_ns = *times.iter().min().unwrap_or(&0);
|
||||||
|
let max_time_ns = *times.iter().max().unwrap_or(&0);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
iterations,
|
||||||
|
total_time_ns,
|
||||||
|
avg_time_ns,
|
||||||
|
min_time_ns,
|
||||||
|
max_time_ns,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print(&self) {
|
||||||
|
info!("Benchmark: {}", self.name);
|
||||||
|
info!(" Iterations: {}", self.iterations);
|
||||||
|
info!(" Total time: {} ns", self.total_time_ns);
|
||||||
|
info!(" Average time: {} ns", self.avg_time_ns);
|
||||||
|
info!(" Min time: {} ns", self.min_time_ns);
|
||||||
|
info!(" Max time: {} ns", self.max_time_ns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Benchmark function type
|
||||||
|
pub type BenchmarkFn = fn();
|
||||||
|
|
||||||
|
/// Run a benchmark
|
||||||
|
pub fn benchmark(name: &str, iterations: u64, func: BenchmarkFn) -> BenchmarkResult {
|
||||||
|
let mut times = Vec::new();
|
||||||
|
|
||||||
|
info!("Running benchmark: {} ({} iterations)", name, iterations);
|
||||||
|
|
||||||
|
for _i in 0..iterations {
|
||||||
|
let start = monotonic_time();
|
||||||
|
func();
|
||||||
|
let end = monotonic_time();
|
||||||
|
|
||||||
|
let elapsed_ns = (end.to_ns() as i64 - start.to_ns() as i64) as u64;
|
||||||
|
times.push(elapsed_ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = BenchmarkResult::new(name.to_string(), iterations, ×);
|
||||||
|
result.print();
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Memory allocation benchmark
|
||||||
|
fn bench_memory_alloc() {
|
||||||
|
let _vec: Vec<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(())
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ pub struct BootInfo {
|
|||||||
pub command_line: Option<alloc::string::String>,
|
pub command_line: Option<alloc::string::String>,
|
||||||
pub initrd_start: Option<usize>,
|
pub initrd_start: Option<usize>,
|
||||||
pub initrd_size: Option<usize>,
|
pub initrd_size: Option<usize>,
|
||||||
|
pub multiboot_addr: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BootInfo {
|
impl BootInfo {
|
||||||
@@ -41,6 +42,7 @@ impl BootInfo {
|
|||||||
command_line: None,
|
command_line: None,
|
||||||
initrd_start: None,
|
initrd_start: None,
|
||||||
initrd_size: None,
|
initrd_size: None,
|
||||||
|
multiboot_addr: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,10 +56,14 @@ pub static mut BOOT_INFO: BootInfo = BootInfo {
|
|||||||
command_line: None,
|
command_line: None,
|
||||||
initrd_start: None,
|
initrd_start: None,
|
||||||
initrd_size: None,
|
initrd_size: None,
|
||||||
|
multiboot_addr: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init() -> Result<()> {
|
/// Set multiboot information address
|
||||||
complete_boot()
|
pub fn set_multiboot_info(addr: usize) {
|
||||||
|
unsafe {
|
||||||
|
BOOT_INFO.multiboot_addr = Some(addr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get boot information
|
/// Get boot information
|
||||||
@@ -65,177 +71,173 @@ pub fn get_boot_info() -> &'static BootInfo {
|
|||||||
unsafe { &BOOT_INFO }
|
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
|
/// Complete boot process
|
||||||
pub fn complete_boot() -> Result<()> {
|
pub fn complete_boot() -> Result<()> {
|
||||||
info!("=== Rust Kernel Boot Process ===");
|
set_boot_stage(BootStage::Complete);
|
||||||
|
info!("Boot process completed successfully");
|
||||||
// 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 });
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Early hardware initialization
|
/// Initialize multiboot information
|
||||||
fn early_hardware_init() -> Result<()> {
|
/// This should be called at the very beginning of kernel execution
|
||||||
info!("Initializing early hardware...");
|
pub fn multiboot_init() {
|
||||||
|
// TODO: Parse multiboot information from bootloader
|
||||||
// Initialize console first
|
// For now, initialize with default values
|
||||||
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
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// Enable SSE/SSE2 if available
|
BOOT_INFO = BootInfo {
|
||||||
let mut cr0: u64;
|
memory_size: 512 * 1024 * 1024, // 512MB default
|
||||||
core::arch::asm!("mov {}, cr0", out(reg) cr0);
|
available_memory: 480 * 1024 * 1024, // 480MB available
|
||||||
cr0 &= !(1 << 2); // Clear EM (emulation) bit
|
cpu_count: 1,
|
||||||
cr0 |= 1 << 1; // Set MP (monitor coprocessor) bit
|
boot_time: 0,
|
||||||
core::arch::asm!("mov cr0, {}", in(reg) cr0);
|
command_line: None,
|
||||||
|
initrd_start: None,
|
||||||
let mut cr4: u64;
|
initrd_size: None,
|
||||||
core::arch::asm!("mov {}, cr4", out(reg) cr4);
|
multiboot_addr: None,
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("x86_64 features initialized");
|
info!("Multiboot information 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(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
221
kernel/src/boot_clean.rs
Archivo normal
221
kernel/src/boot_clean.rs
Archivo normal
@@ -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(())
|
||||||
|
}
|
||||||
@@ -122,7 +122,7 @@ impl Console {
|
|||||||
self.column_position = 0;
|
self.column_position = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_str(&mut self, s: &str) {
|
pub fn write_str(&mut self, s: &str) {
|
||||||
if !self.initialized {
|
if !self.initialized {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -241,6 +241,12 @@ pub fn print_info(message: &str) {
|
|||||||
writer.write_str(message).unwrap();
|
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);
|
struct ConsoleWriter<'a>(&'a mut Console);
|
||||||
|
|
||||||
impl Write for ConsoleWriter<'_> {
|
impl Write for ConsoleWriter<'_> {
|
||||||
|
|||||||
289
kernel/src/diagnostics.rs
Archivo normal
289
kernel/src/diagnostics.rs
Archivo normal
@@ -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
134
kernel/src/drivers_init.rs
Archivo normal
@@ -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
|
||||||
|
];
|
||||||
@@ -92,8 +92,97 @@ pub fn main_init() -> ! {
|
|||||||
}
|
}
|
||||||
info!("Time management initialized");
|
info!("Time management initialized");
|
||||||
|
|
||||||
// TODO: Initialize drivers
|
// Display system information
|
||||||
// init_drivers();
|
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
|
// TODO: Start kernel threads
|
||||||
// start_kernel_threads();
|
// start_kernel_threads();
|
||||||
|
|||||||
@@ -165,15 +165,16 @@ impl InterruptSubsystem {
|
|||||||
pub fn init() -> Result<()> {
|
pub fn init() -> Result<()> {
|
||||||
let mut subsystem = INTERRUPT_SUBSYSTEM.lock();
|
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
|
// Set up standard x86 interrupt vectors
|
||||||
init_standard_interrupts(&mut subsystem)?;
|
init_standard_interrupts(&mut subsystem)?;
|
||||||
|
|
||||||
// Initialize interrupt controller (PIC/APIC)
|
// Initialize interrupt controller (PIC/APIC)
|
||||||
init_interrupt_controller()?;
|
init_interrupt_controller()?;
|
||||||
|
|
||||||
// Set up exception handlers
|
|
||||||
init_exception_handlers()?;
|
|
||||||
|
|
||||||
subsystem.enabled = true;
|
subsystem.enabled = true;
|
||||||
crate::info!("Interrupt subsystem initialized");
|
crate::info!("Interrupt subsystem initialized");
|
||||||
|
|
||||||
@@ -238,7 +239,8 @@ fn init_interrupt_controller() -> Result<()> {
|
|||||||
|
|
||||||
/// Initialize exception handlers
|
/// Initialize exception handlers
|
||||||
fn init_exception_handlers() -> Result<()> {
|
fn init_exception_handlers() -> Result<()> {
|
||||||
init_idt()
|
// Architecture-specific IDT initialization is done in init()
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register an interrupt handler - Linux compatible
|
/// 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
|
/// Register an interrupt handler at a specific vector
|
||||||
pub fn register_interrupt_handler(vector: u32, handler: usize) -> Result<()> {
|
pub fn register_interrupt_handler(vector: u32, handler: usize) -> Result<()> {
|
||||||
if vector > 255 {
|
if vector > 255 {
|
||||||
return Err(Error::InvalidArgument);
|
return Err(Error::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
crate::info!("Registered interrupt handler at vector 0x{:x} -> 0x{:x}", vector, handler);
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exception handlers
|
// 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
|
/// System call interrupt handler
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn syscall_handler() {
|
pub extern "C" fn syscall_handler() {
|
||||||
@@ -547,7 +394,7 @@ pub extern "C" fn syscall_handler() {
|
|||||||
let mut arg5: u64;
|
let mut arg5: u64;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
core::arch::asm!(
|
||||||
"mov {0}, rax",
|
"mov {0}, rax",
|
||||||
"mov {1}, rdi",
|
"mov {1}, rdi",
|
||||||
"mov {2}, rsi",
|
"mov {2}, rsi",
|
||||||
@@ -572,13 +419,13 @@ pub extern "C" fn syscall_handler() {
|
|||||||
|
|
||||||
// Return result in register (rax)
|
// Return result in register (rax)
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
core::arch::asm!(
|
||||||
"mov rax, {0}",
|
"mov rax, {0}",
|
||||||
in(reg) result,
|
in(reg) result,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Return from interrupt
|
// Return from interrupt
|
||||||
asm!("iretq", options(noreturn));
|
core::arch::asm!("iretq", options(noreturn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
192
kernel/src/kthread.rs
Archivo normal
192
kernel/src/kthread.rs
Archivo normal
@@ -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())
|
||||||
|
}
|
||||||
@@ -19,29 +19,43 @@
|
|||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
|
pub mod benchmark; // Performance benchmarking
|
||||||
pub mod boot;
|
pub mod boot;
|
||||||
pub mod console;
|
pub mod console;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub mod device_advanced;
|
pub mod device_advanced;
|
||||||
|
pub mod diagnostics; // System diagnostics and health monitoring
|
||||||
pub mod driver;
|
pub mod driver;
|
||||||
|
pub mod drivers_init; // Driver initialization
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod init;
|
pub mod init;
|
||||||
pub mod interrupt;
|
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 memory;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
|
pub mod module_loader; // Dynamic module loading
|
||||||
|
pub mod net_basic; // Basic networking support
|
||||||
pub mod network;
|
pub mod network;
|
||||||
pub mod panic;
|
pub mod panic;
|
||||||
|
pub mod perf; // Performance monitoring
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod scheduler;
|
pub mod scheduler;
|
||||||
|
pub mod shell; // Kernel shell interface
|
||||||
|
pub mod stress_test; // System stress testing
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod syscall;
|
pub mod syscall;
|
||||||
pub mod syscalls; // New syscall infrastructure
|
pub mod syscalls; // New syscall infrastructure
|
||||||
|
pub mod sysinfo; // System information and hardware detection
|
||||||
pub mod task;
|
pub mod task;
|
||||||
|
pub mod test_init; // Kernel initialization testing
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
pub mod usermode; // User mode program support
|
||||||
|
|
||||||
|
|
||||||
/// Kernel version information
|
/// Kernel version information
|
||||||
@@ -49,8 +63,18 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|||||||
pub const NAME: &str = "Rust Kernel";
|
pub const NAME: &str = "Rust Kernel";
|
||||||
|
|
||||||
/// Kernel entry point called from architecture-specific code
|
/// Kernel entry point called from architecture-specific code
|
||||||
|
/// This is called from the boot assembly with multiboot information
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn kernel_main() -> ! {
|
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::early_init();
|
||||||
init::main_init();
|
init::main_init();
|
||||||
|
|
||||||
@@ -58,6 +82,50 @@ pub extern "C" fn kernel_main() -> ! {
|
|||||||
panic!("kernel_main returned unexpectedly");
|
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
|
/// Test runner for kernel tests
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn test_runner(tests: &[&dyn Fn()]) {
|
fn test_runner(tests: &[&dyn Fn()]) {
|
||||||
|
|||||||
457
kernel/src/logging.rs
Archivo normal
457
kernel/src/logging.rs
Archivo normal
@@ -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
477
kernel/src/memfs.rs
Archivo normal
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -93,6 +93,9 @@ static SLAB_ALLOCATOR: Spinlock<SlabAllocator> = Spinlock::new(SlabAllocator::ne
|
|||||||
|
|
||||||
/// Allocate kernel memory
|
/// Allocate kernel memory
|
||||||
pub fn kmalloc(size: usize) -> Result<*mut u8> {
|
pub fn kmalloc(size: usize) -> Result<*mut u8> {
|
||||||
|
// Increment performance counter
|
||||||
|
crate::perf::counters::inc_memory_allocs();
|
||||||
|
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return Err(Error::InvalidArgument);
|
return Err(Error::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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_ATOMIC: AllocFlags = AllocFlags::new(gfp::GFP_ATOMIC);
|
||||||
pub const GFP_USER: AllocFlags = AllocFlags::new(gfp::GFP_USER);
|
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
|
/// Initialize the memory management subsystem with proper Linux-style initialization
|
||||||
pub fn init() -> Result<()> {
|
pub fn init() -> Result<()> {
|
||||||
allocator::init()?;
|
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
|
/// Allocate a page of physical memory
|
||||||
pub fn alloc_page() -> Result<PhysAddr> {
|
pub fn alloc_page() -> Result<PhysAddr> {
|
||||||
page::alloc_page()
|
page::alloc_page()
|
||||||
@@ -122,12 +178,23 @@ pub fn free_page(addr: PhysAddr) {
|
|||||||
page::free_page(addr)
|
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
|
/// Map a virtual address to a physical address
|
||||||
pub fn map_page(virt: VirtAddr, phys: PhysAddr) -> Result<()> {
|
pub fn map_page(virt: VirtAddr, phys: PhysAddr, flags: PageFlags) -> Result<()> {
|
||||||
// TODO: implement page table mapping
|
// TODO: implement page table mapping with flags
|
||||||
Ok(())
|
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
|
/// Unmap a virtual address
|
||||||
pub fn unmap_page(virt: VirtAddr) -> Result<()> {
|
pub fn unmap_page(virt: VirtAddr) -> Result<()> {
|
||||||
// TODO: implement page table unmapping
|
// TODO: implement page table unmapping
|
||||||
|
|||||||
@@ -93,17 +93,17 @@ pub mod page_flags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Page frame allocator
|
/// 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
|
/// Page allocator implementation
|
||||||
struct PageAllocator {
|
pub struct PageAllocator {
|
||||||
free_pages: BTreeSet<Pfn>,
|
free_pages: BTreeSet<Pfn>,
|
||||||
total_pages: usize,
|
total_pages: usize,
|
||||||
allocated_pages: usize,
|
allocated_pages: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageAllocator {
|
impl PageAllocator {
|
||||||
const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
free_pages: BTreeSet::new(),
|
free_pages: BTreeSet::new(),
|
||||||
total_pages: 0,
|
total_pages: 0,
|
||||||
@@ -112,7 +112,7 @@ impl PageAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add a range of pages to the free list
|
/// 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 {
|
for i in 0..count {
|
||||||
self.free_pages.insert(Pfn(start.0 + i));
|
self.free_pages.insert(Pfn(start.0 + i));
|
||||||
}
|
}
|
||||||
@@ -157,6 +157,22 @@ pub fn init() -> Result<()> {
|
|||||||
Ok(())
|
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
|
/// Allocate a page of physical memory
|
||||||
pub fn alloc_page() -> Result<PhysAddr> {
|
pub fn alloc_page() -> Result<PhysAddr> {
|
||||||
let mut allocator = PAGE_ALLOCATOR.lock();
|
let mut allocator = PAGE_ALLOCATOR.lock();
|
||||||
@@ -164,6 +180,11 @@ pub fn alloc_page() -> Result<PhysAddr> {
|
|||||||
Ok(pfn.to_phys_addr())
|
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
|
/// Free a page of physical memory
|
||||||
pub fn free_page(addr: PhysAddr) {
|
pub fn free_page(addr: PhysAddr) {
|
||||||
let pfn = Pfn::from_phys_addr(addr);
|
let pfn = Pfn::from_phys_addr(addr);
|
||||||
|
|||||||
314
kernel/src/module_loader.rs
Archivo normal
314
kernel/src/module_loader.rs
Archivo normal
@@ -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
198
kernel/src/net_basic.rs
Archivo normal
@@ -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
318
kernel/src/perf.rs
Archivo normal
@@ -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
904
kernel/src/shell.rs
Archivo normal
@@ -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
267
kernel/src/stress_test.rs
Archivo normal
@@ -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
366
kernel/src/sysinfo.rs
Archivo normal
@@ -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
150
kernel/src/test_init.rs
Archivo normal
@@ -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(())
|
||||||
|
}
|
||||||
@@ -153,6 +153,12 @@ pub struct Irq(pub u32);
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Jiffies(pub u64);
|
pub struct Jiffies(pub u64);
|
||||||
|
|
||||||
|
impl Jiffies {
|
||||||
|
pub fn as_u64(self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Mul<u64> for Jiffies {
|
impl Mul<u64> for Jiffies {
|
||||||
type Output = u64;
|
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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Nanoseconds(pub u64);
|
pub struct Nanoseconds(pub u64);
|
||||||
|
|
||||||
|
|||||||
350
kernel/src/usermode.rs
Archivo normal
350
kernel/src/usermode.rs
Archivo normal
@@ -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())
|
||||||
|
}
|
||||||
@@ -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",
|
|
||||||
}
|
|
||||||
@@ -8,8 +8,5 @@
|
|||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
pub mod hello;
|
// Module infrastructure is ready for dynamic modules
|
||||||
pub mod test;
|
// Modules can be loaded at runtime through the module_loader system
|
||||||
|
|
||||||
pub use hello::*;
|
|
||||||
pub use test::*;
|
|
||||||
|
|||||||
@@ -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
42
test.sh
@@ -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/"
|
|
||||||
Referencia en una nueva incidencia
Block a user