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.
|
||||
12
Cargo.toml
12
Cargo.toml
@@ -19,20 +19,12 @@ kernel = { path = "kernel" }
|
||||
[dependencies]
|
||||
kernel = { path = "kernel" }
|
||||
|
||||
[lib]
|
||||
name = "rust_kernel"
|
||||
crate-type = ["staticlib", "cdylib"]
|
||||
|
||||
[features]
|
||||
default = ["alloc", "std"]
|
||||
alloc = []
|
||||
std = []
|
||||
no_std = []
|
||||
|
||||
# Workspace-level profile configuration
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
opt-level = 0
|
||||
debug = true
|
||||
lto = false
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
7
Makefile
7
Makefile
@@ -66,8 +66,13 @@ clippy:
|
||||
doc:
|
||||
$(CARGO) doc $(CARGO_FLAGS) --no-deps
|
||||
|
||||
# Test the kernel
|
||||
test-kernel: kernel
|
||||
@echo "Testing kernel functionality"
|
||||
cd kernel && $(CARGO) test $(CARGO_FLAGS)
|
||||
|
||||
# Install (placeholder)
|
||||
install:
|
||||
@echo "Install target not implemented yet"
|
||||
|
||||
.PHONY: all kernel modules drivers clean test fmt-check fmt clippy doc install
|
||||
.PHONY: all kernel modules drivers clean test fmt-check fmt clippy doc test-kernel install
|
||||
|
||||
197
README.md
197
README.md
@@ -1,53 +1,168 @@
|
||||
# Rust Kernel
|
||||
|
||||
A modern, experimental kernel written in Rust, inspired by the Linux kernel architecture and designed for x86_64 systems.
|
||||
A modern, experimental x86_64 kernel written in Rust with advanced monitoring, diagnostics, and stress testing capabilities.
|
||||
|
||||
## Overview
|
||||
|
||||
This project implements a basic operating system kernel in Rust, featuring:
|
||||
|
||||
- **Memory Management**: Page allocation, virtual memory, slab allocator, and buddy allocator
|
||||
- **Process Management**: Process creation, scheduling, context switching, and signal handling
|
||||
- **File System**: Virtual File System (VFS) with ramfs, procfs, and devfs implementations
|
||||
- **Device Management**: Advanced device driver framework with power management
|
||||
- **Network Stack**: Basic networking with interface management, ARP, and routing
|
||||
- **System Calls**: Linux-compatible system call interface
|
||||
- **Interrupt Handling**: x86_64 IDT setup and exception handling
|
||||
- **Boot Process**: Staged hardware initialization and kernel setup
|
||||
|
||||
## Architecture
|
||||
|
||||
The kernel is organized into the following main components:
|
||||
## Features
|
||||
|
||||
### Core Systems
|
||||
- `lib.rs` - Main kernel entry point and module declarations
|
||||
- `prelude.rs` - Common imports and essential types
|
||||
- `error.rs` - Kernel error types and errno mappings
|
||||
- `types.rs` - Fundamental kernel data types (PIDs, UIDs, device IDs, etc.)
|
||||
- **Memory Management**: Page allocation, kmalloc/vmalloc, physical/virtual memory mapping
|
||||
- **Process Management**: Basic process structures, kernel threads, scheduling framework
|
||||
- **File System**: In-memory file system (memfs) with shell integration
|
||||
- **Device Drivers**: PS/2 keyboard, serial console, basic device framework
|
||||
- **Network Stack**: Basic networking with loopback interface and statistics
|
||||
- **Module System**: Dynamic module loading with dependency management
|
||||
- **System Calls**: Basic syscall infrastructure and user mode support
|
||||
|
||||
### Memory Management (`memory/`)
|
||||
- `page.rs` - Physical page frame allocation and management
|
||||
- `allocator.rs` - High-level memory allocation interfaces
|
||||
- `kmalloc.rs` - Kernel memory allocation (slab allocator)
|
||||
- `vmalloc.rs` - Virtual memory allocation and VMA tracking
|
||||
- `page_table.rs` - Page table management and virtual memory mapping
|
||||
### Advanced Features
|
||||
- **System Diagnostics**: Real-time health monitoring with categorized diagnostics
|
||||
- **Performance Monitoring**: Comprehensive performance counters and analysis
|
||||
- **Stress Testing**: Memory, CPU, and filesystem stress testing with metrics
|
||||
- **Advanced Logging**: Multi-level logging with filtering and statistics
|
||||
- **System Information**: Detailed hardware detection and system reporting
|
||||
- **Interactive Shell**: 20+ commands for system administration and testing
|
||||
|
||||
### Process Management
|
||||
- `process.rs` - Process and thread structures, fork/exec/wait/exit
|
||||
- `scheduler.rs` - Process scheduling and task switching
|
||||
- `task.rs` - Task management and process lists
|
||||
### Architecture Support
|
||||
- **x86_64**: Complete support with GDT, IDT, paging, and exception handling
|
||||
- **Boot Process**: Multiboot-compatible with staged initialization
|
||||
- **Hardware Detection**: CPUID-based CPU information and feature detection
|
||||
|
||||
### File System (`fs/`)
|
||||
- `mod.rs` - VFS core and file system registration
|
||||
- `file.rs` - File descriptor management and operations
|
||||
- `inode.rs` - Inode operations and metadata
|
||||
- `dentry.rs` - Directory entry cache
|
||||
- `super_block.rs` - File system superblock management
|
||||
- `ramfs.rs` - RAM-based file system implementation
|
||||
- `procfs.rs` - Process information file system
|
||||
- `devfs.rs` - Device file system
|
||||
## Quick Start
|
||||
|
||||
### Device Management
|
||||
### Prerequisites
|
||||
- Rust nightly toolchain
|
||||
- NASM assembler
|
||||
- Make
|
||||
- QEMU (for testing)
|
||||
|
||||
### Building
|
||||
```bash
|
||||
# Build the kernel
|
||||
make kernel
|
||||
|
||||
# Build in debug mode
|
||||
RUSTFLAGS="-Awarnings" make kernel
|
||||
|
||||
# Clean build artifacts
|
||||
make clean
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
```
|
||||
├── kernel/ # Core kernel implementation
|
||||
│ ├── src/
|
||||
│ │ ├── lib.rs # Kernel entry point
|
||||
│ │ ├── arch/ # Architecture-specific code (x86_64)
|
||||
│ │ ├── memory/ # Memory management subsystem
|
||||
│ │ ├── fs/ # File system implementation
|
||||
│ │ └── ... # Other subsystems
|
||||
├── drivers/ # Device drivers
|
||||
├── modules/ # Loadable kernel modules
|
||||
└── src/ # Top-level crate wrapper
|
||||
```
|
||||
|
||||
## Shell Commands
|
||||
|
||||
The kernel includes an interactive shell with comprehensive system administration commands:
|
||||
|
||||
### System Information
|
||||
- `info` - Basic system information
|
||||
- `sysinfo [show|compact|benchmark]` - Detailed system information
|
||||
- `mem` - Memory statistics
|
||||
- `uptime` - System uptime
|
||||
|
||||
### Diagnostics and Health
|
||||
- `diag [report|check|clear|critical]` - System diagnostics
|
||||
- `health [status|check|monitor]` - Health monitoring
|
||||
- `stress <type> [duration]` - Stress testing (memory, cpu, filesystem, all)
|
||||
|
||||
### Performance Monitoring
|
||||
- `perf [report|clear|counters|reset]` - Performance monitoring
|
||||
- `bench [list|run|all|stress]` - Built-in benchmarks
|
||||
- `log [show|clear|level|stats]` - Advanced logging
|
||||
|
||||
### File System
|
||||
- `ls [path]` - List directory contents
|
||||
- `cat <file>` - Display file contents
|
||||
- `mkdir <path>` - Create directory
|
||||
- `touch <file>` - Create file
|
||||
- `rm <path>` - Remove file/directory
|
||||
|
||||
### Development
|
||||
- `test [all|memory|fs|module]` - Run kernel tests
|
||||
- `mod [list|test|unload]` - Module management
|
||||
- `exec <program>` - Execute user programs
|
||||
- `clear` - Clear screen
|
||||
- `help` - Show all commands
|
||||
|
||||
## Key Features
|
||||
|
||||
### System Diagnostics
|
||||
- Real-time health monitoring with automatic issue detection
|
||||
- Categorized diagnostics (Memory, CPU, I/O, Network, FileSystem, Process, Kernel)
|
||||
- Historical tracking with timestamps for trend analysis
|
||||
- Critical issue alerts with detailed reporting
|
||||
|
||||
### Stress Testing
|
||||
- **Memory Tests**: Rapid allocation/deallocation with leak detection
|
||||
- **CPU Tests**: Intensive calculations for performance validation
|
||||
- **Filesystem Tests**: File operations stress testing
|
||||
- Performance metrics: operations/second, error rates, duration tracking
|
||||
|
||||
### Performance Monitoring
|
||||
- Comprehensive performance counters
|
||||
- Real-time system metrics
|
||||
- Benchmark suite for system validation
|
||||
- Integration with stress testing for performance analysis
|
||||
|
||||
### Advanced Logging
|
||||
- Multi-level logging (debug, info, warn, error)
|
||||
- Structured log entries with timestamps
|
||||
- Filtering and search capabilities
|
||||
- Statistics and analysis tools
|
||||
|
||||
## Development
|
||||
|
||||
### Architecture
|
||||
The kernel follows a modular design with clear separation of concerns:
|
||||
|
||||
- **Core**: Essential kernel functionality and initialization
|
||||
- **Memory**: Physical/virtual memory management with allocators
|
||||
- **Process**: Process management and kernel threading
|
||||
- **FileSystem**: VFS with in-memory implementation
|
||||
- **Devices**: Driver framework with basic hardware support
|
||||
- **Network**: Basic networking stack with interface management
|
||||
- **Shell**: Interactive command interface for administration
|
||||
|
||||
### Error Handling
|
||||
Robust error handling throughout with:
|
||||
- Structured error types with detailed information
|
||||
- Result-based error propagation
|
||||
- Diagnostic integration for automatic issue tracking
|
||||
- Recovery mechanisms where possible
|
||||
|
||||
### Testing
|
||||
Comprehensive testing framework including:
|
||||
- Unit tests for individual components
|
||||
- Integration tests for subsystem interaction
|
||||
- Stress tests for reliability validation
|
||||
- Performance benchmarks for optimization
|
||||
|
||||
## License
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
This project is licensed under the GNU General Public License v2.0.
|
||||
|
||||
## Contributing
|
||||
|
||||
This is an experimental kernel project for research and educational purposes.
|
||||
Contributions are welcome through pull requests and issue reports.
|
||||
|
||||
## Status
|
||||
|
||||
**Experimental** - This kernel is in active development and not suitable for production use.
|
||||
It serves as a platform for operating system research, Rust kernel development,
|
||||
and educational purposes.
|
||||
- `device.rs` - Basic device abstraction
|
||||
- `device_advanced.rs` - Advanced device driver framework with power management
|
||||
- `driver.rs` - Device driver registration and management
|
||||
|
||||
@@ -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;
|
||||
|
||||
pub mod dummy;
|
||||
pub mod mem;
|
||||
pub mod platform_example;
|
||||
pub mod ramdisk;
|
||||
pub mod keyboard; // New keyboard driver
|
||||
pub mod serial; // New serial driver
|
||||
|
||||
pub use dummy::*;
|
||||
pub use mem::*;
|
||||
pub use platform_example::*;
|
||||
pub mod keyboard; // Keyboard driver
|
||||
pub mod serial; // Serial driver
|
||||
pub use ramdisk::*;
|
||||
|
||||
@@ -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 = []
|
||||
smp = [] # Symmetric Multi-Processing
|
||||
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
|
||||
|
||||
//! GDT stub
|
||||
pub fn init() {}
|
||||
//! Global Descriptor Table (GDT) for x86_64
|
||||
|
||||
use core::mem::size_of;
|
||||
|
||||
/// GDT Entry structure
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
pub struct GdtEntry {
|
||||
pub limit_low: u16,
|
||||
pub base_low: u16,
|
||||
pub base_middle: u8,
|
||||
pub access: u8,
|
||||
pub granularity: u8,
|
||||
pub base_high: u8,
|
||||
}
|
||||
|
||||
impl GdtEntry {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
limit_low: 0,
|
||||
base_low: 0,
|
||||
base_middle: 0,
|
||||
access: 0,
|
||||
granularity: 0,
|
||||
base_high: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_segment(&mut self, base: u32, limit: u32, access: u8, granularity: u8) {
|
||||
self.base_low = (base & 0xFFFF) as u16;
|
||||
self.base_middle = ((base >> 16) & 0xFF) as u8;
|
||||
self.base_high = ((base >> 24) & 0xFF) as u8;
|
||||
|
||||
self.limit_low = (limit & 0xFFFF) as u16;
|
||||
self.granularity = ((limit >> 16) & 0x0F) as u8 | (granularity & 0xF0);
|
||||
|
||||
self.access = access;
|
||||
}
|
||||
}
|
||||
|
||||
/// GDT Pointer structure
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
pub struct GdtPointer {
|
||||
pub limit: u16,
|
||||
pub base: u64,
|
||||
}
|
||||
|
||||
/// GDT constants
|
||||
pub const GDT_ENTRIES: usize = 5;
|
||||
|
||||
/// GDT access byte flags
|
||||
pub mod access {
|
||||
pub const PRESENT: u8 = 1 << 7;
|
||||
pub const RING_0: u8 = 0 << 5;
|
||||
pub const RING_1: u8 = 1 << 5;
|
||||
pub const RING_2: u8 = 2 << 5;
|
||||
pub const RING_3: u8 = 3 << 5;
|
||||
pub const SYSTEM: u8 = 1 << 4;
|
||||
pub const EXECUTABLE: u8 = 1 << 3;
|
||||
pub const CONFORMING: u8 = 1 << 2;
|
||||
pub const READABLE: u8 = 1 << 1;
|
||||
pub const WRITABLE: u8 = 1 << 1;
|
||||
pub const ACCESSED: u8 = 1 << 0;
|
||||
}
|
||||
|
||||
/// GDT granularity flags
|
||||
pub mod granularity {
|
||||
pub const GRANULARITY_4K: u8 = 1 << 7;
|
||||
pub const SIZE_32: u8 = 1 << 6;
|
||||
pub const LONG_MODE: u8 = 1 << 5;
|
||||
}
|
||||
|
||||
/// Global GDT
|
||||
static mut GDT: [GdtEntry; GDT_ENTRIES] = [GdtEntry::new(); GDT_ENTRIES];
|
||||
|
||||
/// Initialize GDT
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
// Null descriptor
|
||||
GDT[0] = GdtEntry::new();
|
||||
|
||||
// Kernel code segment (64-bit)
|
||||
GDT[1].set_segment(
|
||||
0x00000000,
|
||||
0xFFFFF,
|
||||
access::PRESENT | access::RING_0 | access::SYSTEM | access::EXECUTABLE | access::READABLE,
|
||||
granularity::GRANULARITY_4K | granularity::LONG_MODE
|
||||
);
|
||||
|
||||
// Kernel data segment (64-bit)
|
||||
GDT[2].set_segment(
|
||||
0x00000000,
|
||||
0xFFFFF,
|
||||
access::PRESENT | access::RING_0 | access::SYSTEM | access::WRITABLE,
|
||||
granularity::GRANULARITY_4K | granularity::LONG_MODE
|
||||
);
|
||||
|
||||
// User code segment (64-bit)
|
||||
GDT[3].set_segment(
|
||||
0x00000000,
|
||||
0xFFFFF,
|
||||
access::PRESENT | access::RING_3 | access::SYSTEM | access::EXECUTABLE | access::READABLE,
|
||||
granularity::GRANULARITY_4K | granularity::LONG_MODE
|
||||
);
|
||||
|
||||
// User data segment (64-bit)
|
||||
GDT[4].set_segment(
|
||||
0x00000000,
|
||||
0xFFFFF,
|
||||
access::PRESENT | access::RING_3 | access::SYSTEM | access::WRITABLE,
|
||||
granularity::GRANULARITY_4K | granularity::LONG_MODE
|
||||
);
|
||||
|
||||
let gdt_ptr = GdtPointer {
|
||||
limit: (size_of::<[GdtEntry; GDT_ENTRIES]>() - 1) as u16,
|
||||
base: GDT.as_ptr() as u64,
|
||||
};
|
||||
|
||||
// Load GDT
|
||||
core::arch::asm!(
|
||||
"lgdt [{}]",
|
||||
in(reg) &gdt_ptr,
|
||||
options(nostack, preserves_flags)
|
||||
);
|
||||
|
||||
// Reload segment registers
|
||||
core::arch::asm!(
|
||||
"mov ax, 0x10", // Kernel data segment
|
||||
"mov ds, ax",
|
||||
"mov es, ax",
|
||||
"mov fs, ax",
|
||||
"mov gs, ax",
|
||||
"mov ss, ax",
|
||||
out("ax") _,
|
||||
options(nostack, preserves_flags)
|
||||
);
|
||||
|
||||
// Far jump to reload CS
|
||||
core::arch::asm!(
|
||||
"push 0x08", // Kernel code segment
|
||||
"lea rax, [rip + 2f]",
|
||||
"push rax",
|
||||
"retfq",
|
||||
"2:",
|
||||
out("rax") _,
|
||||
options(nostack, preserves_flags)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,492 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//! IDT stub
|
||||
pub fn init() {}
|
||||
//! Interrupt Descriptor Table (IDT) for x86_64
|
||||
|
||||
use core::mem::size_of;
|
||||
|
||||
/// IDT Entry structure for x86_64
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
pub struct IdtEntry {
|
||||
pub offset_low: u16, // Handler function address bits 0-15
|
||||
pub selector: u16, // Code segment selector
|
||||
pub ist: u8, // Interrupt stack table offset
|
||||
pub type_attr: u8, // Type and attributes
|
||||
pub offset_middle: u16, // Handler function address bits 16-31
|
||||
pub offset_high: u32, // Handler function address bits 32-63
|
||||
pub zero: u32, // Reserved, must be zero
|
||||
}
|
||||
|
||||
impl IdtEntry {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
offset_low: 0,
|
||||
selector: 0,
|
||||
ist: 0,
|
||||
type_attr: 0,
|
||||
offset_middle: 0,
|
||||
offset_high: 0,
|
||||
zero: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_handler(&mut self, handler: extern "C" fn(), selector: u16, type_attr: u8) {
|
||||
let addr = handler as u64;
|
||||
|
||||
self.offset_low = (addr & 0xFFFF) as u16;
|
||||
self.offset_middle = ((addr >> 16) & 0xFFFF) as u16;
|
||||
self.offset_high = ((addr >> 32) & 0xFFFFFFFF) as u32;
|
||||
|
||||
self.selector = selector;
|
||||
self.type_attr = type_attr;
|
||||
self.ist = 0;
|
||||
self.zero = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// IDT Pointer structure
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
pub struct IdtPointer {
|
||||
pub limit: u16,
|
||||
pub base: u64,
|
||||
}
|
||||
|
||||
/// IDT constants
|
||||
pub const IDT_ENTRIES: usize = 256;
|
||||
|
||||
/// IDT type and attribute flags
|
||||
pub mod type_attr {
|
||||
pub const PRESENT: u8 = 1 << 7;
|
||||
pub const RING_0: u8 = 0 << 5;
|
||||
pub const RING_1: u8 = 1 << 5;
|
||||
pub const RING_2: u8 = 2 << 5;
|
||||
pub const RING_3: u8 = 3 << 5;
|
||||
pub const INTERRUPT_GATE: u8 = 0x0E;
|
||||
pub const TRAP_GATE: u8 = 0x0F;
|
||||
pub const TASK_GATE: u8 = 0x05;
|
||||
}
|
||||
|
||||
/// Global IDT
|
||||
static mut IDT: [IdtEntry; IDT_ENTRIES] = [IdtEntry::new(); IDT_ENTRIES];
|
||||
|
||||
/// Exception handler stubs implemented in Rust
|
||||
#[no_mangle]
|
||||
pub extern "C" fn divide_error_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 0, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_divide_error(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn debug_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 1, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_debug(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn nmi_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 2, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_nmi(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn breakpoint_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 3, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_breakpoint(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn overflow_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 4, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_overflow(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn bound_range_exceeded_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 5, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_bound_range_exceeded(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn invalid_opcode_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 6, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_invalid_opcode(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn device_not_available_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 7, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_device_not_available(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn double_fault_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 8, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_double_fault(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn invalid_tss_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 10, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_invalid_tss(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn segment_not_present_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 11, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_segment_not_present(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn stack_segment_fault_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 12, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_stack_segment_fault(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn general_protection_fault_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 13, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_general_protection_fault(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn page_fault_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 14, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_page_fault(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn x87_fpu_error_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 16, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_x87_fpu_error(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn alignment_check_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 17, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_alignment_check(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn machine_check_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 18, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_machine_check(&ctx);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn simd_exception_handler() {
|
||||
let ctx = ExceptionContext {
|
||||
gs: 0, fs: 0, es: 0, ds: 0,
|
||||
r15: 0, r14: 0, r13: 0, r12: 0, r11: 0, r10: 0, r9: 0, r8: 0,
|
||||
rdi: 0, rsi: 0, rbp: 0, rbx: 0, rdx: 0, rcx: 0, rax: 0,
|
||||
vector: 19, error_code: 0,
|
||||
rip: 0, cs: 0, eflags: 0, rsp: 0, ss: 0,
|
||||
};
|
||||
handle_simd_exception(&ctx);
|
||||
}
|
||||
|
||||
/// Initialize IDT
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
// Set up exception handlers
|
||||
IDT[0].set_handler(divide_error_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[1].set_handler(debug_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[2].set_handler(nmi_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[3].set_handler(breakpoint_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE | type_attr::RING_3);
|
||||
IDT[4].set_handler(overflow_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[5].set_handler(bound_range_exceeded_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[6].set_handler(invalid_opcode_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[7].set_handler(device_not_available_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[8].set_handler(double_fault_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[10].set_handler(invalid_tss_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[11].set_handler(segment_not_present_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[12].set_handler(stack_segment_fault_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[13].set_handler(general_protection_fault_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[14].set_handler(page_fault_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[16].set_handler(x87_fpu_error_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[17].set_handler(alignment_check_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[18].set_handler(machine_check_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
IDT[19].set_handler(simd_exception_handler, 0x08, type_attr::PRESENT | type_attr::INTERRUPT_GATE);
|
||||
|
||||
let idt_ptr = IdtPointer {
|
||||
limit: (size_of::<[IdtEntry; IDT_ENTRIES]>() - 1) as u16,
|
||||
base: IDT.as_ptr() as u64,
|
||||
};
|
||||
|
||||
// Load IDT
|
||||
core::arch::asm!(
|
||||
"lidt [{}]",
|
||||
in(reg) &idt_ptr,
|
||||
options(nostack, preserves_flags)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Exception context structure passed from assembly
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct ExceptionContext {
|
||||
// Segment registers
|
||||
pub gs: u64,
|
||||
pub fs: u64,
|
||||
pub es: u64,
|
||||
pub ds: u64,
|
||||
|
||||
// General purpose registers
|
||||
pub r15: u64,
|
||||
pub r14: u64,
|
||||
pub r13: u64,
|
||||
pub r12: u64,
|
||||
pub r11: u64,
|
||||
pub r10: u64,
|
||||
pub r9: u64,
|
||||
pub r8: u64,
|
||||
pub rdi: u64,
|
||||
pub rsi: u64,
|
||||
pub rbp: u64,
|
||||
pub rbx: u64,
|
||||
pub rdx: u64,
|
||||
pub rcx: u64,
|
||||
pub rax: u64,
|
||||
|
||||
// Exception information
|
||||
pub vector: u64,
|
||||
pub error_code: u64,
|
||||
|
||||
// Interrupt stack frame
|
||||
pub rip: u64,
|
||||
pub cs: u64,
|
||||
pub eflags: u64,
|
||||
pub rsp: u64,
|
||||
pub ss: u64,
|
||||
}
|
||||
|
||||
/// Exception handler called from assembly
|
||||
#[no_mangle]
|
||||
pub extern "C" fn exception_handler(context: *const ExceptionContext) {
|
||||
let ctx = unsafe { &*context };
|
||||
|
||||
match ctx.vector {
|
||||
0 => handle_divide_error(ctx),
|
||||
1 => handle_debug(ctx),
|
||||
2 => handle_nmi(ctx),
|
||||
3 => handle_breakpoint(ctx),
|
||||
4 => handle_overflow(ctx),
|
||||
5 => handle_bound_range_exceeded(ctx),
|
||||
6 => handle_invalid_opcode(ctx),
|
||||
7 => handle_device_not_available(ctx),
|
||||
8 => handle_double_fault(ctx),
|
||||
10 => handle_invalid_tss(ctx),
|
||||
11 => handle_segment_not_present(ctx),
|
||||
12 => handle_stack_segment_fault(ctx),
|
||||
13 => handle_general_protection_fault(ctx),
|
||||
14 => handle_page_fault(ctx),
|
||||
16 => handle_x87_fpu_error(ctx),
|
||||
17 => handle_alignment_check(ctx),
|
||||
18 => handle_machine_check(ctx),
|
||||
19 => handle_simd_exception(ctx),
|
||||
_ => handle_unknown_exception(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
// Individual exception handlers
|
||||
fn handle_divide_error(ctx: &ExceptionContext) {
|
||||
crate::error!("Divide by zero error at RIP: 0x{:x}", ctx.rip);
|
||||
panic!("Divide by zero exception");
|
||||
}
|
||||
|
||||
fn handle_debug(ctx: &ExceptionContext) {
|
||||
crate::info!("Debug exception at RIP: 0x{:x}", ctx.rip);
|
||||
}
|
||||
|
||||
fn handle_nmi(ctx: &ExceptionContext) {
|
||||
crate::error!("Non-maskable interrupt at RIP: 0x{:x}", ctx.rip);
|
||||
}
|
||||
|
||||
fn handle_breakpoint(ctx: &ExceptionContext) {
|
||||
crate::info!("Breakpoint at RIP: 0x{:x}", ctx.rip);
|
||||
}
|
||||
|
||||
fn handle_overflow(ctx: &ExceptionContext) {
|
||||
crate::error!("Overflow exception at RIP: 0x{:x}", ctx.rip);
|
||||
panic!("Overflow exception");
|
||||
}
|
||||
|
||||
fn handle_bound_range_exceeded(ctx: &ExceptionContext) {
|
||||
crate::error!("Bound range exceeded at RIP: 0x{:x}", ctx.rip);
|
||||
panic!("Bound range exceeded");
|
||||
}
|
||||
|
||||
fn handle_invalid_opcode(ctx: &ExceptionContext) {
|
||||
crate::error!("Invalid opcode at RIP: 0x{:x}", ctx.rip);
|
||||
panic!("Invalid opcode");
|
||||
}
|
||||
|
||||
fn handle_device_not_available(ctx: &ExceptionContext) {
|
||||
crate::error!("Device not available at RIP: 0x{:x}", ctx.rip);
|
||||
panic!("Device not available");
|
||||
}
|
||||
|
||||
fn handle_double_fault(ctx: &ExceptionContext) {
|
||||
crate::error!("Double fault at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code);
|
||||
panic!("Double fault");
|
||||
}
|
||||
|
||||
fn handle_invalid_tss(ctx: &ExceptionContext) {
|
||||
crate::error!("Invalid TSS at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code);
|
||||
panic!("Invalid TSS");
|
||||
}
|
||||
|
||||
fn handle_segment_not_present(ctx: &ExceptionContext) {
|
||||
crate::error!("Segment not present at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code);
|
||||
panic!("Segment not present");
|
||||
}
|
||||
|
||||
fn handle_stack_segment_fault(ctx: &ExceptionContext) {
|
||||
crate::error!("Stack segment fault at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code);
|
||||
panic!("Stack segment fault");
|
||||
}
|
||||
|
||||
fn handle_general_protection_fault(ctx: &ExceptionContext) {
|
||||
crate::error!("General protection fault at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code);
|
||||
panic!("General protection fault");
|
||||
}
|
||||
|
||||
fn handle_page_fault(ctx: &ExceptionContext) {
|
||||
// Get the faulting address from CR2
|
||||
let fault_addr: u64;
|
||||
unsafe {
|
||||
core::arch::asm!("mov {}, cr2", out(reg) fault_addr);
|
||||
}
|
||||
|
||||
crate::error!("Page fault at RIP: 0x{:x}, fault address: 0x{:x}, error code: 0x{:x}",
|
||||
ctx.rip, fault_addr, ctx.error_code);
|
||||
panic!("Page fault");
|
||||
}
|
||||
|
||||
fn handle_x87_fpu_error(ctx: &ExceptionContext) {
|
||||
crate::error!("x87 FPU error at RIP: 0x{:x}", ctx.rip);
|
||||
panic!("x87 FPU error");
|
||||
}
|
||||
|
||||
fn handle_alignment_check(ctx: &ExceptionContext) {
|
||||
crate::error!("Alignment check at RIP: 0x{:x}, error code: 0x{:x}", ctx.rip, ctx.error_code);
|
||||
panic!("Alignment check");
|
||||
}
|
||||
|
||||
fn handle_machine_check(ctx: &ExceptionContext) {
|
||||
crate::error!("Machine check at RIP: 0x{:x}", ctx.rip);
|
||||
panic!("Machine check");
|
||||
}
|
||||
|
||||
fn handle_simd_exception(ctx: &ExceptionContext) {
|
||||
crate::error!("SIMD exception at RIP: 0x{:x}", ctx.rip);
|
||||
panic!("SIMD exception");
|
||||
}
|
||||
|
||||
fn handle_unknown_exception(ctx: &ExceptionContext) {
|
||||
crate::error!("Unknown exception {} at RIP: 0x{:x}", ctx.vector, ctx.rip);
|
||||
panic!("Unknown exception");
|
||||
}
|
||||
|
||||
@@ -30,3 +30,25 @@ impl Port {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a byte from a port
|
||||
pub unsafe fn inb(port: u16) -> u8 {
|
||||
let value: u8;
|
||||
core::arch::asm!(
|
||||
"in al, dx",
|
||||
out("al") value,
|
||||
in("dx") port,
|
||||
options(nomem, nostack, preserves_flags)
|
||||
);
|
||||
value
|
||||
}
|
||||
|
||||
/// Write a byte to a port
|
||||
pub unsafe fn outb(port: u16, value: u8) {
|
||||
core::arch::asm!(
|
||||
"out dx, al",
|
||||
in("dx") port,
|
||||
in("al") value,
|
||||
options(nomem, nostack, preserves_flags)
|
||||
);
|
||||
}
|
||||
|
||||
188
kernel/src/benchmark.rs
Archivo normal
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 initrd_start: Option<usize>,
|
||||
pub initrd_size: Option<usize>,
|
||||
pub multiboot_addr: Option<usize>,
|
||||
}
|
||||
|
||||
impl BootInfo {
|
||||
@@ -41,6 +42,7 @@ impl BootInfo {
|
||||
command_line: None,
|
||||
initrd_start: None,
|
||||
initrd_size: None,
|
||||
multiboot_addr: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,10 +56,14 @@ pub static mut BOOT_INFO: BootInfo = BootInfo {
|
||||
command_line: None,
|
||||
initrd_start: None,
|
||||
initrd_size: None,
|
||||
multiboot_addr: None,
|
||||
};
|
||||
|
||||
pub fn init() -> Result<()> {
|
||||
complete_boot()
|
||||
/// Set multiboot information address
|
||||
pub fn set_multiboot_info(addr: usize) {
|
||||
unsafe {
|
||||
BOOT_INFO.multiboot_addr = Some(addr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get boot information
|
||||
@@ -65,177 +71,173 @@ pub fn get_boot_info() -> &'static BootInfo {
|
||||
unsafe { &BOOT_INFO }
|
||||
}
|
||||
|
||||
/// Update boot information
|
||||
pub unsafe fn update_boot_info<F>(f: F) where F: FnOnce(&mut BootInfo) {
|
||||
f(&mut BOOT_INFO);
|
||||
}
|
||||
|
||||
pub mod multiboot {
|
||||
use crate::types::{PhysAddr, VirtAddr};
|
||||
use crate::error::Result;
|
||||
use crate::info;
|
||||
|
||||
/// Multiboot2 information structure
|
||||
#[repr(C)]
|
||||
pub struct MultibootInfo {
|
||||
pub total_size: u32,
|
||||
pub reserved: u32,
|
||||
}
|
||||
|
||||
/// Memory map entry from multiboot
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct MemoryMapEntry {
|
||||
pub base_addr: u64,
|
||||
pub length: u64,
|
||||
pub type_: u32,
|
||||
pub reserved: u32,
|
||||
}
|
||||
|
||||
/// Memory map types
|
||||
pub mod memory_type {
|
||||
pub const AVAILABLE: u32 = 1;
|
||||
pub const RESERVED: u32 = 2;
|
||||
pub const ACPI_RECLAIMABLE: u32 = 3;
|
||||
pub const NVS: u32 = 4;
|
||||
pub const BADRAM: u32 = 5;
|
||||
}
|
||||
|
||||
/// Boot memory information
|
||||
#[derive(Debug)]
|
||||
pub struct BootMemoryInfo {
|
||||
pub total_memory: u64,
|
||||
pub available_memory: u64,
|
||||
pub memory_regions: alloc::vec::Vec<MemoryMapEntry>,
|
||||
}
|
||||
|
||||
impl BootMemoryInfo {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
total_memory: 0,
|
||||
available_memory: 0,
|
||||
memory_regions: alloc::vec::Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_region(&mut self, entry: MemoryMapEntry) {
|
||||
if entry.type_ == memory_type::AVAILABLE {
|
||||
self.available_memory += entry.length;
|
||||
}
|
||||
self.total_memory += entry.length;
|
||||
self.memory_regions.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse multiboot2 information and initialize memory management
|
||||
pub fn init_memory_from_multiboot(multiboot_addr: usize) -> Result<()> {
|
||||
info!("Parsing multiboot information at 0x{:x}", multiboot_addr);
|
||||
|
||||
let multiboot_info = unsafe { &*(multiboot_addr as *const MultibootInfo) };
|
||||
|
||||
info!("Multiboot info size: {} bytes", multiboot_info.total_size);
|
||||
|
||||
// Parse memory map from multiboot info
|
||||
let mut memory_info = BootMemoryInfo::new();
|
||||
|
||||
// For now, assume a basic memory layout if we can't parse multiboot properly
|
||||
// This is a fallback to make the kernel bootable
|
||||
let default_memory = MemoryMapEntry {
|
||||
base_addr: 0x100000, // 1MB
|
||||
length: 0x7F00000, // ~127MB (assuming 128MB total RAM)
|
||||
type_: memory_type::AVAILABLE,
|
||||
reserved: 0,
|
||||
};
|
||||
|
||||
memory_info.add_region(default_memory);
|
||||
|
||||
// Update global boot info
|
||||
unsafe {
|
||||
super::update_boot_info(|boot_info| {
|
||||
boot_info.memory_size = memory_info.total_memory as usize;
|
||||
boot_info.available_memory = memory_info.available_memory as usize;
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize page allocator with available memory
|
||||
for region in &memory_info.memory_regions {
|
||||
if region.type_ == memory_type::AVAILABLE {
|
||||
let start_pfn = region.base_addr / 4096;
|
||||
let end_pfn = (region.base_addr + region.length) / 4096;
|
||||
|
||||
info!("Adding memory region: 0x{:x}-0x{:x}",
|
||||
region.base_addr, region.base_addr + region.length);
|
||||
|
||||
// Add this memory region to the page allocator
|
||||
crate::memory::page::add_free_range(
|
||||
PhysAddr::new(region.base_addr as usize),
|
||||
PhysAddr::new((region.base_addr + region.length) as usize)
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
info!("Memory initialization from multiboot completed");
|
||||
info!("Total memory: {} bytes", memory_info.total_memory);
|
||||
info!("Available memory: {} bytes", memory_info.available_memory);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Early boot setup before memory allocation is available
|
||||
pub fn early_boot_setup() -> Result<()> {
|
||||
info!("Early boot setup");
|
||||
|
||||
// Basic hardware initialization
|
||||
// This is done before memory allocators are available
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Boot stage management
|
||||
static mut CURRENT_BOOT_STAGE: BootStage = BootStage::EarlyInit;
|
||||
|
||||
/// Get current boot stage
|
||||
pub fn get_boot_stage() -> BootStage {
|
||||
unsafe { CURRENT_BOOT_STAGE }
|
||||
}
|
||||
|
||||
/// Set boot stage
|
||||
pub fn set_boot_stage(stage: BootStage) {
|
||||
unsafe {
|
||||
CURRENT_BOOT_STAGE = stage;
|
||||
}
|
||||
info!("Boot stage: {:?}", stage);
|
||||
}
|
||||
|
||||
/// Complete boot process
|
||||
pub fn complete_boot() -> Result<()> {
|
||||
info!("=== Rust Kernel Boot Process ===");
|
||||
|
||||
// Stage 1: Early initialization
|
||||
info!("Stage 1: Early initialization");
|
||||
early_hardware_init()?;
|
||||
|
||||
// Stage 2: Memory management
|
||||
info!("Stage 2: Memory management initialization");
|
||||
crate::memory::init()?;
|
||||
crate::memory::kmalloc::init()?;
|
||||
crate::memory::vmalloc::init()?;
|
||||
|
||||
// Stage 3: Interrupt handling
|
||||
info!("Stage 3: Interrupt handling initialization");
|
||||
crate::interrupt::init()?;
|
||||
|
||||
// Stage 4: Device management
|
||||
info!("Stage 4: Device management initialization");
|
||||
crate::device::init()?;
|
||||
crate::device_advanced::init_advanced()?;
|
||||
|
||||
// Stage 5: Process and scheduler
|
||||
info!("Stage 5: Process and scheduler initialization");
|
||||
crate::process::init()?;
|
||||
crate::scheduler::init()?;
|
||||
|
||||
// Stage 6: File system
|
||||
info!("Stage 6: File system initialization");
|
||||
crate::fs::init()?;
|
||||
|
||||
// Stage 7: Network stack
|
||||
info!("Stage 7: Network stack initialization");
|
||||
crate::network::init()?;
|
||||
|
||||
// Stage 8: Load initial ramdisk
|
||||
if let Some(initrd_start) = unsafe { BOOT_INFO.initrd_start } {
|
||||
info!("Stage 8: Loading initial ramdisk from 0x{:x}", initrd_start);
|
||||
load_initrd(initrd_start, unsafe { BOOT_INFO.initrd_size.unwrap_or(0) })?;
|
||||
} else {
|
||||
info!("Stage 8: No initial ramdisk found");
|
||||
}
|
||||
|
||||
// Stage 9: Start init process
|
||||
info!("Stage 9: Starting init process");
|
||||
start_init_process()?;
|
||||
|
||||
info!("=== Boot Complete ===");
|
||||
info!("Kernel version: {} v{}", crate::NAME, crate::VERSION);
|
||||
info!("Total memory: {} MB", unsafe { BOOT_INFO.memory_size } / 1024 / 1024);
|
||||
info!("Available memory: {} MB", unsafe { BOOT_INFO.available_memory } / 1024 / 1024);
|
||||
info!("CPU count: {}", unsafe { BOOT_INFO.cpu_count });
|
||||
|
||||
set_boot_stage(BootStage::Complete);
|
||||
info!("Boot process completed successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Early hardware initialization
|
||||
fn early_hardware_init() -> Result<()> {
|
||||
info!("Initializing early hardware...");
|
||||
|
||||
// Initialize console first
|
||||
crate::console::init()?;
|
||||
|
||||
// Detect CPU features
|
||||
detect_cpu_features()?;
|
||||
|
||||
// Initialize architecture-specific features
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
init_x86_64_features()?;
|
||||
|
||||
// Detect memory layout
|
||||
detect_memory_layout()?;
|
||||
|
||||
info!("Early hardware initialization complete");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Detect CPU features
|
||||
fn detect_cpu_features() -> Result<()> {
|
||||
info!("Detecting CPU features...");
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
// TODO: Implement CPUID detection without register conflicts
|
||||
// For now, just log that we're skipping detailed CPU detection
|
||||
info!("CPU Vendor: Unknown (CPUID detection disabled)");
|
||||
info!("CPU Features: Basic x86_64 assumed");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Initialize x86_64-specific features
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn init_x86_64_features() -> Result<()> {
|
||||
info!("Initializing x86_64 features...");
|
||||
|
||||
// Initialize GDT (Global Descriptor Table)
|
||||
// TODO: Set up proper GDT with kernel/user segments
|
||||
|
||||
// Enable important CPU features
|
||||
/// Initialize multiboot information
|
||||
/// This should be called at the very beginning of kernel execution
|
||||
pub fn multiboot_init() {
|
||||
// TODO: Parse multiboot information from bootloader
|
||||
// For now, initialize with default values
|
||||
unsafe {
|
||||
// Enable SSE/SSE2 if available
|
||||
let mut cr0: u64;
|
||||
core::arch::asm!("mov {}, cr0", out(reg) cr0);
|
||||
cr0 &= !(1 << 2); // Clear EM (emulation) bit
|
||||
cr0 |= 1 << 1; // Set MP (monitor coprocessor) bit
|
||||
core::arch::asm!("mov cr0, {}", in(reg) cr0);
|
||||
|
||||
let mut cr4: u64;
|
||||
core::arch::asm!("mov {}, cr4", out(reg) cr4);
|
||||
cr4 |= 1 << 9; // Set OSFXSR (OS supports FXSAVE/FXRSTOR)
|
||||
cr4 |= 1 << 10; // Set OSXMMEXCPT (OS supports unmasked SIMD FP exceptions)
|
||||
core::arch::asm!("mov cr4, {}", in(reg) cr4);
|
||||
BOOT_INFO = BootInfo {
|
||||
memory_size: 512 * 1024 * 1024, // 512MB default
|
||||
available_memory: 480 * 1024 * 1024, // 480MB available
|
||||
cpu_count: 1,
|
||||
boot_time: 0,
|
||||
command_line: None,
|
||||
initrd_start: None,
|
||||
initrd_size: None,
|
||||
multiboot_addr: None,
|
||||
};
|
||||
}
|
||||
|
||||
info!("x86_64 features initialized");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Detect memory layout
|
||||
fn detect_memory_layout() -> Result<()> {
|
||||
info!("Detecting memory layout...");
|
||||
|
||||
// For now, use conservative defaults
|
||||
// In a real implementation, this would parse multiboot info or UEFI memory map
|
||||
unsafe {
|
||||
BOOT_INFO.memory_size = 128 * 1024 * 1024; // 128 MB default
|
||||
BOOT_INFO.available_memory = 64 * 1024 * 1024; // 64 MB available
|
||||
BOOT_INFO.cpu_count = 1;
|
||||
}
|
||||
|
||||
info!("Memory layout detected: {} MB total, {} MB available",
|
||||
unsafe { BOOT_INFO.memory_size } / 1024 / 1024,
|
||||
unsafe { BOOT_INFO.available_memory } / 1024 / 1024);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Load initial ramdisk
|
||||
fn load_initrd(_start: usize, _size: usize) -> Result<()> {
|
||||
info!("Loading initial ramdisk...");
|
||||
|
||||
// TODO: Parse and mount initrd as root filesystem
|
||||
// This would involve:
|
||||
// 1. Validating the initrd format (cpio, tar, etc.)
|
||||
// 2. Creating a ramdisk device
|
||||
// 3. Mounting it as the root filesystem
|
||||
// 4. Extracting files to the ramdisk
|
||||
|
||||
info!("Initial ramdisk loaded");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Start init process
|
||||
fn start_init_process() -> Result<()> {
|
||||
info!("Starting init process...");
|
||||
|
||||
// Create init process (PID 1)
|
||||
let init_pid = crate::process::create_process(
|
||||
"/sbin/init".to_string(),
|
||||
crate::types::Uid(0), // root
|
||||
crate::types::Gid(0), // root
|
||||
)?;
|
||||
|
||||
info!("Init process started with PID {}", init_pid.0);
|
||||
|
||||
// TODO: Load init binary from filesystem
|
||||
// TODO: Set up initial environment
|
||||
// TODO: Start init process execution
|
||||
|
||||
Ok(())
|
||||
info!("Multiboot information initialized");
|
||||
}
|
||||
|
||||
221
kernel/src/boot_clean.rs
Archivo normal
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;
|
||||
}
|
||||
|
||||
fn write_str(&mut self, s: &str) {
|
||||
pub fn write_str(&mut self, s: &str) {
|
||||
if !self.initialized {
|
||||
return;
|
||||
}
|
||||
@@ -241,6 +241,12 @@ pub fn print_info(message: &str) {
|
||||
writer.write_str(message).unwrap();
|
||||
}
|
||||
|
||||
/// Write string to console
|
||||
pub fn write_str(s: &str) {
|
||||
let mut console = CONSOLE.lock();
|
||||
console.write_str(s);
|
||||
}
|
||||
|
||||
struct ConsoleWriter<'a>(&'a mut Console);
|
||||
|
||||
impl Write for ConsoleWriter<'_> {
|
||||
|
||||
289
kernel/src/diagnostics.rs
Archivo normal
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");
|
||||
|
||||
// TODO: Initialize drivers
|
||||
// init_drivers();
|
||||
// Display system information
|
||||
crate::test_init::display_system_info();
|
||||
|
||||
// Run basic functionality tests
|
||||
if let Err(e) = crate::test_init::run_basic_tests() {
|
||||
error!("Basic functionality tests failed: {}", e);
|
||||
panic!("Basic tests failed");
|
||||
}
|
||||
|
||||
// Run initialization tests
|
||||
if let Err(e) = crate::test_init::run_init_tests() {
|
||||
error!("Initialization tests failed: {}", e);
|
||||
panic!("Initialization tests failed");
|
||||
}
|
||||
|
||||
// Initialize drivers
|
||||
if let Err(e) = crate::drivers_init::init_drivers() {
|
||||
error!("Failed to initialize drivers: {}", e);
|
||||
panic!("Driver initialization failed");
|
||||
}
|
||||
info!("Drivers initialized");
|
||||
|
||||
// Initialize kernel threads
|
||||
if let Err(e) = crate::kthread::init_kthreads() {
|
||||
error!("Failed to initialize kernel threads: {}", e);
|
||||
panic!("Kernel thread initialization failed");
|
||||
}
|
||||
info!("Kernel threads initialized");
|
||||
|
||||
// Initialize kernel shell
|
||||
if let Err(e) = crate::shell::init_shell() {
|
||||
error!("Failed to initialize kernel shell: {}", e);
|
||||
panic!("Shell initialization failed");
|
||||
}
|
||||
info!("Kernel shell initialized");
|
||||
|
||||
// Initialize basic networking
|
||||
if let Err(e) = crate::net_basic::init_networking() {
|
||||
error!("Failed to initialize networking: {}", e);
|
||||
panic!("Networking initialization failed");
|
||||
}
|
||||
info!("Basic networking initialized");
|
||||
|
||||
// Initialize module loading system
|
||||
if let Err(e) = crate::module_loader::init_modules() {
|
||||
error!("Failed to initialize module system: {}", e);
|
||||
panic!("Module system initialization failed");
|
||||
}
|
||||
info!("Module system initialized");
|
||||
|
||||
// Initialize in-memory file system
|
||||
if let Err(e) = crate::memfs::init_memfs() {
|
||||
error!("Failed to initialize file system: {}", e);
|
||||
panic!("File system initialization failed");
|
||||
}
|
||||
info!("In-memory file system initialized");
|
||||
|
||||
// Initialize user mode support
|
||||
if let Err(e) = crate::usermode::init_usermode() {
|
||||
error!("Failed to initialize user mode: {}", e);
|
||||
panic!("User mode initialization failed");
|
||||
}
|
||||
info!("User mode support initialized");
|
||||
|
||||
// Initialize performance monitoring
|
||||
if let Err(e) = crate::perf::init_perf_monitor() {
|
||||
error!("Failed to initialize performance monitoring: {}", e);
|
||||
panic!("Performance monitoring initialization failed");
|
||||
}
|
||||
info!("Performance monitoring initialized");
|
||||
|
||||
// Initialize advanced logging system
|
||||
if let Err(e) = crate::logging::init_logging() {
|
||||
error!("Failed to initialize logging system: {}", e);
|
||||
panic!("Logging system initialization failed");
|
||||
}
|
||||
info!("Advanced logging system initialized");
|
||||
|
||||
// Initialize system information collection
|
||||
if let Err(e) = crate::sysinfo::init_sysinfo() {
|
||||
error!("Failed to initialize system information: {}", e);
|
||||
panic!("System information initialization failed");
|
||||
}
|
||||
info!("System information collection initialized");
|
||||
|
||||
// Initialize system diagnostics
|
||||
if let Err(e) = crate::diagnostics::init_diagnostics() {
|
||||
error!("Failed to initialize system diagnostics: {}", e);
|
||||
panic!("System diagnostics initialization failed");
|
||||
}
|
||||
info!("System diagnostics initialized");
|
||||
|
||||
// TODO: Start kernel threads
|
||||
// start_kernel_threads();
|
||||
|
||||
@@ -165,15 +165,16 @@ impl InterruptSubsystem {
|
||||
pub fn init() -> Result<()> {
|
||||
let mut subsystem = INTERRUPT_SUBSYSTEM.lock();
|
||||
|
||||
// Initialize architecture-specific interrupt handling
|
||||
crate::arch::x86_64::gdt::init();
|
||||
crate::arch::x86_64::idt::init();
|
||||
|
||||
// Set up standard x86 interrupt vectors
|
||||
init_standard_interrupts(&mut subsystem)?;
|
||||
|
||||
// Initialize interrupt controller (PIC/APIC)
|
||||
init_interrupt_controller()?;
|
||||
|
||||
// Set up exception handlers
|
||||
init_exception_handlers()?;
|
||||
|
||||
subsystem.enabled = true;
|
||||
crate::info!("Interrupt subsystem initialized");
|
||||
|
||||
@@ -238,7 +239,8 @@ fn init_interrupt_controller() -> Result<()> {
|
||||
|
||||
/// Initialize exception handlers
|
||||
fn init_exception_handlers() -> Result<()> {
|
||||
init_idt()
|
||||
// Architecture-specific IDT initialization is done in init()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Register an interrupt handler - Linux compatible
|
||||
@@ -364,172 +366,17 @@ pub fn disable_irq(irq: u32) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
/// IDT (Interrupt Descriptor Table) management
|
||||
pub mod idt {
|
||||
use super::*;
|
||||
|
||||
/// IDT Entry structure (x86_64)
|
||||
#[repr(C, packed)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct IdtEntry {
|
||||
offset_low: u16,
|
||||
selector: u16,
|
||||
ist: u8,
|
||||
type_attr: u8,
|
||||
offset_mid: u16,
|
||||
offset_high: u32,
|
||||
reserved: u32,
|
||||
}
|
||||
|
||||
impl IdtEntry {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
offset_low: 0,
|
||||
selector: 0,
|
||||
ist: 0,
|
||||
type_attr: 0,
|
||||
offset_mid: 0,
|
||||
offset_high: 0,
|
||||
reserved: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_handler(&mut self, handler: usize, selector: u16, ist: u8, type_attr: u8) {
|
||||
self.offset_low = (handler & 0xFFFF) as u16;
|
||||
self.offset_mid = ((handler >> 16) & 0xFFFF) as u16;
|
||||
self.offset_high = ((handler >> 32) & 0xFFFFFFFF) as u32;
|
||||
self.selector = selector;
|
||||
self.ist = ist;
|
||||
self.type_attr = type_attr;
|
||||
}
|
||||
}
|
||||
|
||||
/// IDT Table
|
||||
#[repr(C, packed)]
|
||||
pub struct Idt {
|
||||
entries: [IdtEntry; 256],
|
||||
}
|
||||
|
||||
impl Idt {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
entries: [IdtEntry::new(); 256],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_handler(&mut self, vector: u8, handler: usize) {
|
||||
self.entries[vector as usize].set_handler(
|
||||
handler,
|
||||
0x08, // Kernel code segment
|
||||
0, // No IST
|
||||
0x8E, // Present, DPL=0, Interrupt Gate
|
||||
);
|
||||
}
|
||||
|
||||
pub fn load(&self) {
|
||||
let idt_ptr = IdtPtr {
|
||||
limit: (core::mem::size_of::<Idt>() - 1) as u16,
|
||||
base: self as *const _ as u64,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
asm!("lidt [{}]", in(reg) &idt_ptr, options(readonly, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct IdtPtr {
|
||||
limit: u16,
|
||||
base: u64,
|
||||
}
|
||||
}
|
||||
|
||||
use idt::Idt;
|
||||
static mut IDT: Idt = Idt::new();
|
||||
|
||||
/// Register an interrupt handler at a specific vector
|
||||
pub fn register_interrupt_handler(vector: u32, handler: usize) -> Result<()> {
|
||||
if vector > 255 {
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
IDT.set_handler(vector as u8, handler);
|
||||
crate::info!("Registered interrupt handler at vector 0x{:x} -> 0x{:x}", vector, handler);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Initialize and load the IDT
|
||||
pub fn init_idt() -> Result<()> {
|
||||
unsafe {
|
||||
// Set up basic exception handlers
|
||||
IDT.set_handler(0, divide_by_zero_handler as usize);
|
||||
IDT.set_handler(1, debug_handler as usize);
|
||||
IDT.set_handler(3, breakpoint_handler as usize);
|
||||
IDT.set_handler(6, invalid_opcode_handler as usize);
|
||||
IDT.set_handler(8, double_fault_handler as usize);
|
||||
IDT.set_handler(13, general_protection_handler as usize);
|
||||
IDT.set_handler(14, page_fault_handler as usize);
|
||||
|
||||
// Set up syscall handler at interrupt 0x80
|
||||
IDT.set_handler(0x80, syscall_handler as usize);
|
||||
|
||||
// Load the IDT
|
||||
IDT.load();
|
||||
crate::info!("IDT initialized and loaded");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Exception handlers
|
||||
#[no_mangle]
|
||||
extern "C" fn divide_by_zero_handler() {
|
||||
crate::error!("Division by zero exception");
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn debug_handler() {
|
||||
crate::info!("Debug exception");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn breakpoint_handler() {
|
||||
crate::info!("Breakpoint exception");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn invalid_opcode_handler() {
|
||||
crate::error!("Invalid opcode exception");
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn double_fault_handler() {
|
||||
crate::error!("Double fault exception");
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn general_protection_handler() {
|
||||
crate::error!("General protection fault");
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn page_fault_handler() {
|
||||
let mut cr2: u64;
|
||||
unsafe {
|
||||
asm!("mov {}, cr2", out(reg) cr2);
|
||||
}
|
||||
crate::error!("Page fault at address 0x{:x}", cr2);
|
||||
loop {}
|
||||
}
|
||||
|
||||
/// System call interrupt handler
|
||||
#[no_mangle]
|
||||
pub extern "C" fn syscall_handler() {
|
||||
@@ -547,7 +394,7 @@ pub extern "C" fn syscall_handler() {
|
||||
let mut arg5: u64;
|
||||
|
||||
unsafe {
|
||||
asm!(
|
||||
core::arch::asm!(
|
||||
"mov {0}, rax",
|
||||
"mov {1}, rdi",
|
||||
"mov {2}, rsi",
|
||||
@@ -572,13 +419,13 @@ pub extern "C" fn syscall_handler() {
|
||||
|
||||
// Return result in register (rax)
|
||||
unsafe {
|
||||
asm!(
|
||||
core::arch::asm!(
|
||||
"mov rax, {0}",
|
||||
in(reg) result,
|
||||
);
|
||||
|
||||
// Return from interrupt
|
||||
asm!("iretq", options(noreturn));
|
||||
core::arch::asm!("iretq", options(noreturn));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
192
kernel/src/kthread.rs
Archivo normal
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;
|
||||
|
||||
pub mod arch;
|
||||
pub mod benchmark; // Performance benchmarking
|
||||
pub mod boot;
|
||||
pub mod console;
|
||||
pub mod cpu;
|
||||
pub mod device;
|
||||
pub mod device_advanced;
|
||||
pub mod diagnostics; // System diagnostics and health monitoring
|
||||
pub mod driver;
|
||||
pub mod drivers_init; // Driver initialization
|
||||
pub mod error;
|
||||
pub mod fs;
|
||||
pub mod init;
|
||||
pub mod interrupt;
|
||||
pub mod kthread; // Kernel thread management
|
||||
pub mod logging; // Kernel logging and debugging
|
||||
pub mod memfs; // In-memory file system
|
||||
pub mod memory;
|
||||
pub mod module;
|
||||
pub mod module_loader; // Dynamic module loading
|
||||
pub mod net_basic; // Basic networking support
|
||||
pub mod network;
|
||||
pub mod panic;
|
||||
pub mod perf; // Performance monitoring
|
||||
pub mod prelude;
|
||||
pub mod process;
|
||||
pub mod scheduler;
|
||||
pub mod shell; // Kernel shell interface
|
||||
pub mod stress_test; // System stress testing
|
||||
pub mod sync;
|
||||
pub mod syscall;
|
||||
pub mod syscalls; // New syscall infrastructure
|
||||
pub mod sysinfo; // System information and hardware detection
|
||||
pub mod task;
|
||||
pub mod test_init; // Kernel initialization testing
|
||||
pub mod time;
|
||||
pub mod types;
|
||||
pub mod usermode; // User mode program support
|
||||
|
||||
|
||||
/// Kernel version information
|
||||
@@ -49,8 +63,18 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
pub const NAME: &str = "Rust Kernel";
|
||||
|
||||
/// Kernel entry point called from architecture-specific code
|
||||
/// This is called from the boot assembly with multiboot information
|
||||
#[no_mangle]
|
||||
pub extern "C" fn kernel_main() -> ! {
|
||||
// Early initialization without memory allocation
|
||||
early_kernel_init();
|
||||
|
||||
// Initialize memory management
|
||||
if let Err(e) = memory_init() {
|
||||
panic!("Memory initialization failed: {:?}", e);
|
||||
}
|
||||
|
||||
// Now we can use allocations, continue with full initialization
|
||||
init::early_init();
|
||||
init::main_init();
|
||||
|
||||
@@ -58,6 +82,50 @@ pub extern "C" fn kernel_main() -> ! {
|
||||
panic!("kernel_main returned unexpectedly");
|
||||
}
|
||||
|
||||
/// Kernel entry point with multiboot parameters
|
||||
#[no_mangle]
|
||||
pub extern "C" fn kernel_main_multiboot(multiboot_magic: u32, multiboot_addr: u32) -> ! {
|
||||
// Verify multiboot magic number
|
||||
if multiboot_magic != 0x36d76289 {
|
||||
panic!("Invalid multiboot magic: 0x{:x}", multiboot_magic);
|
||||
}
|
||||
|
||||
// Store multiboot information
|
||||
boot::set_multiboot_info(multiboot_addr as usize);
|
||||
|
||||
// Continue with normal boot
|
||||
kernel_main();
|
||||
}
|
||||
|
||||
/// Early kernel initialization before memory allocator is available
|
||||
fn early_kernel_init() {
|
||||
// Initialize console first so we can print messages
|
||||
if let Err(_) = console::init() {
|
||||
// Can't print error since console isn't initialized
|
||||
loop {}
|
||||
}
|
||||
|
||||
info!("Rust Kernel v{} starting...", VERSION);
|
||||
info!("Early kernel initialization");
|
||||
}
|
||||
|
||||
/// Initialize memory management using multiboot information
|
||||
fn memory_init() -> Result<(), error::Error> {
|
||||
if let Some(multiboot_addr) = boot::get_boot_info().multiboot_addr {
|
||||
boot::multiboot::init_memory_from_multiboot(multiboot_addr)?;
|
||||
} else {
|
||||
// Fallback: initialize with default memory layout
|
||||
memory::page::init()?;
|
||||
}
|
||||
|
||||
// Initialize heap allocator
|
||||
memory::kmalloc::init()?;
|
||||
memory::vmalloc::init()?;
|
||||
|
||||
info!("Memory management initialized");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test runner for kernel tests
|
||||
#[cfg(test)]
|
||||
fn test_runner(tests: &[&dyn Fn()]) {
|
||||
|
||||
457
kernel/src/logging.rs
Archivo normal
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
|
||||
pub fn kmalloc(size: usize) -> Result<*mut u8> {
|
||||
// Increment performance counter
|
||||
crate::perf::counters::inc_memory_allocs();
|
||||
|
||||
if size == 0 {
|
||||
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_USER: AllocFlags = AllocFlags::new(gfp::GFP_USER);
|
||||
|
||||
/// Page mapping flags
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub struct PageFlags(u64);
|
||||
|
||||
impl PageFlags {
|
||||
pub const PRESENT: PageFlags = PageFlags(1 << 0);
|
||||
pub const WRITABLE: PageFlags = PageFlags(1 << 1);
|
||||
pub const USER: PageFlags = PageFlags(1 << 2);
|
||||
pub const EXECUTABLE: PageFlags = PageFlags(1 << 63); // NX bit inverted
|
||||
|
||||
pub const fn new(flags: u64) -> Self {
|
||||
Self(flags)
|
||||
}
|
||||
|
||||
pub fn as_raw(self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn contains(self, flags: PageFlags) -> bool {
|
||||
(self.0 & flags.0) == flags.0
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::BitOr for PageFlags {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
PageFlags(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the memory management subsystem with proper Linux-style initialization
|
||||
pub fn init() -> Result<()> {
|
||||
allocator::init()?;
|
||||
@@ -112,6 +143,31 @@ pub fn memory_info() -> MemoryInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/// Memory statistics for diagnostics
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemoryStats {
|
||||
pub total: usize,
|
||||
pub used: usize,
|
||||
pub free: usize,
|
||||
pub usage_percent: usize,
|
||||
}
|
||||
|
||||
/// Get memory statistics for diagnostics
|
||||
pub fn get_memory_stats() -> Result<MemoryStats> {
|
||||
let info = memory_info();
|
||||
let total = if info.total_pages > 0 { info.total_pages * 4096 } else { 64 * 1024 * 1024 }; // Default 64MB
|
||||
let used = info.used_pages * 4096;
|
||||
let free = total - used;
|
||||
let usage_percent = if total > 0 { (used * 100) / total } else { 0 };
|
||||
|
||||
Ok(MemoryStats {
|
||||
total,
|
||||
used,
|
||||
free,
|
||||
usage_percent,
|
||||
})
|
||||
}
|
||||
|
||||
/// Allocate a page of physical memory
|
||||
pub fn alloc_page() -> Result<PhysAddr> {
|
||||
page::alloc_page()
|
||||
@@ -122,12 +178,23 @@ pub fn free_page(addr: PhysAddr) {
|
||||
page::free_page(addr)
|
||||
}
|
||||
|
||||
/// Allocate a page of physical memory
|
||||
pub fn allocate_page() -> Result<PhysAddr> {
|
||||
page::allocate_page()
|
||||
}
|
||||
|
||||
/// Map a virtual address to a physical address
|
||||
pub fn map_page(virt: VirtAddr, phys: PhysAddr) -> Result<()> {
|
||||
// TODO: implement page table mapping
|
||||
pub fn map_page(virt: VirtAddr, phys: PhysAddr, flags: PageFlags) -> Result<()> {
|
||||
// TODO: implement page table mapping with flags
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Map a virtual address to a physical address (simple version)
|
||||
pub fn map_page_simple(virt: VirtAddr, phys: PhysAddr) -> Result<()> {
|
||||
// TODO: implement page table mapping
|
||||
map_page(virt, phys, PageFlags::PRESENT | PageFlags::WRITABLE)
|
||||
}
|
||||
|
||||
/// Unmap a virtual address
|
||||
pub fn unmap_page(virt: VirtAddr) -> Result<()> {
|
||||
// TODO: implement page table unmapping
|
||||
|
||||
@@ -93,17 +93,17 @@ pub mod page_flags {
|
||||
}
|
||||
|
||||
/// Page frame allocator
|
||||
static PAGE_ALLOCATOR: Spinlock<PageAllocator> = Spinlock::new(PageAllocator::new());
|
||||
pub static PAGE_ALLOCATOR: Spinlock<PageAllocator> = Spinlock::new(PageAllocator::new());
|
||||
|
||||
/// Page allocator implementation
|
||||
struct PageAllocator {
|
||||
pub struct PageAllocator {
|
||||
free_pages: BTreeSet<Pfn>,
|
||||
total_pages: usize,
|
||||
allocated_pages: usize,
|
||||
}
|
||||
|
||||
impl PageAllocator {
|
||||
const fn new() -> Self {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
free_pages: BTreeSet::new(),
|
||||
total_pages: 0,
|
||||
@@ -112,7 +112,7 @@ impl PageAllocator {
|
||||
}
|
||||
|
||||
/// Add a range of pages to the free list
|
||||
fn add_free_range(&mut self, start: Pfn, count: usize) {
|
||||
pub fn add_free_range(&mut self, start: Pfn, count: usize) {
|
||||
for i in 0..count {
|
||||
self.free_pages.insert(Pfn(start.0 + i));
|
||||
}
|
||||
@@ -157,6 +157,22 @@ pub fn init() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a range of free pages by physical address
|
||||
pub fn add_free_range(start_addr: PhysAddr, end_addr: PhysAddr) -> Result<()> {
|
||||
let start_pfn = Pfn::from_phys_addr(start_addr);
|
||||
let end_pfn = Pfn::from_phys_addr(end_addr);
|
||||
|
||||
if end_pfn.0 <= start_pfn.0 {
|
||||
return Err(crate::error::Error::InvalidArgument);
|
||||
}
|
||||
|
||||
let count = end_pfn.0 - start_pfn.0;
|
||||
let mut allocator = PAGE_ALLOCATOR.lock();
|
||||
allocator.add_free_range(start_pfn, count);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Allocate a page of physical memory
|
||||
pub fn alloc_page() -> Result<PhysAddr> {
|
||||
let mut allocator = PAGE_ALLOCATOR.lock();
|
||||
@@ -164,6 +180,11 @@ pub fn alloc_page() -> Result<PhysAddr> {
|
||||
Ok(pfn.to_phys_addr())
|
||||
}
|
||||
|
||||
/// Allocate a page of physical memory (alias for alloc_page)
|
||||
pub fn allocate_page() -> Result<PhysAddr> {
|
||||
alloc_page()
|
||||
}
|
||||
|
||||
/// Free a page of physical memory
|
||||
pub fn free_page(addr: PhysAddr) {
|
||||
let pfn = Pfn::from_phys_addr(addr);
|
||||
|
||||
314
kernel/src/module_loader.rs
Archivo normal
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)]
|
||||
pub struct Jiffies(pub u64);
|
||||
|
||||
impl Jiffies {
|
||||
pub fn as_u64(self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<u64> for Jiffies {
|
||||
type Output = u64;
|
||||
|
||||
@@ -161,6 +167,22 @@ impl Mul<u64> for Jiffies {
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Add<u64> for Jiffies {
|
||||
type Output = Jiffies;
|
||||
|
||||
fn add(self, rhs: u64) -> Self::Output {
|
||||
Jiffies(self.0 + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Sub<Jiffies> for Jiffies {
|
||||
type Output = Jiffies;
|
||||
|
||||
fn sub(self, rhs: Jiffies) -> Self::Output {
|
||||
Jiffies(self.0.saturating_sub(rhs.0))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Nanoseconds(pub u64);
|
||||
|
||||
|
||||
350
kernel/src/usermode.rs
Archivo normal
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;
|
||||
|
||||
pub mod hello;
|
||||
pub mod test;
|
||||
|
||||
pub use hello::*;
|
||||
pub use test::*;
|
||||
// Module infrastructure is ready for dynamic modules
|
||||
// Modules can be loaded at runtime through the module_loader system
|
||||
|
||||
@@ -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