initial commit

Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2025-12-10 23:54:47 +01:00
commit 128c2d6e13
Se han modificado 95 ficheros con 26156 adiciones y 0 borrados

473
kernel/src/advanced_perf.rs Archivo normal
Ver fichero

@@ -0,0 +1,473 @@
// SPDX-License-Identifier: GPL-2.0
//! Advanced performance monitoring and profiling system
use alloc::{
collections::BTreeMap,
string::{String, ToString},
vec::Vec,
};
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use crate::error::{Error, Result};
use crate::sync::Spinlock;
use crate::types::Jiffies;
/// Performance counter types
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CounterType {
CpuCycles,
Instructions,
CacheMisses,
PageFaults,
ContextSwitches,
SystemCalls,
Interrupts,
MemoryAllocations,
DiskReads,
DiskWrites,
NetworkPackets,
Custom(u32),
}
/// Performance event structure
#[derive(Debug, Clone)]
pub struct PerformanceEvent {
pub counter_type: CounterType,
pub value: u64,
pub timestamp: Jiffies,
pub process_id: Option<u32>,
pub thread_id: Option<u32>,
pub cpu_id: Option<u8>,
}
/// Performance counter
#[derive(Debug)]
pub struct PerformanceCounter {
pub counter_type: CounterType,
pub value: AtomicU64,
pub enabled: AtomicBool,
pub last_reset: AtomicU64,
pub description: String,
}
impl PerformanceCounter {
pub fn new(counter_type: CounterType, description: String) -> Self {
Self {
counter_type,
value: AtomicU64::new(0),
enabled: AtomicBool::new(true),
last_reset: AtomicU64::new(crate::time::get_jiffies().0),
description,
}
}
pub fn increment(&self, amount: u64) {
if self.enabled.load(Ordering::Relaxed) {
self.value.fetch_add(amount, Ordering::Relaxed);
}
}
pub fn get_value(&self) -> u64 {
self.value.load(Ordering::Relaxed)
}
pub fn reset(&self) {
self.value.store(0, Ordering::Relaxed);
self.last_reset
.store(crate::time::get_jiffies().0, Ordering::Relaxed);
}
pub fn enable(&self) {
self.enabled.store(true, Ordering::Relaxed);
}
pub fn disable(&self) {
self.enabled.store(false, Ordering::Relaxed);
}
}
/// Performance profiler for function/code block profiling
#[derive(Debug)]
pub struct Profiler {
pub name: String,
pub call_count: AtomicU64,
pub total_time: AtomicU64,
pub min_time: AtomicU64,
pub max_time: AtomicU64,
pub enabled: AtomicBool,
}
impl Profiler {
pub fn new(name: String) -> Self {
Self {
name,
call_count: AtomicU64::new(0),
total_time: AtomicU64::new(0),
min_time: AtomicU64::new(u64::MAX),
max_time: AtomicU64::new(0),
enabled: AtomicBool::new(true),
}
}
pub fn record_execution(&self, duration: u64) {
if !self.enabled.load(Ordering::Relaxed) {
return;
}
self.call_count.fetch_add(1, Ordering::Relaxed);
self.total_time.fetch_add(duration, Ordering::Relaxed);
// Update min time
let mut current_min = self.min_time.load(Ordering::Relaxed);
while duration < current_min {
match self.min_time.compare_exchange_weak(
current_min,
duration,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => break,
Err(x) => current_min = x,
}
}
// Update max time
let mut current_max = self.max_time.load(Ordering::Relaxed);
while duration > current_max {
match self.max_time.compare_exchange_weak(
current_max,
duration,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => break,
Err(x) => current_max = x,
}
}
}
pub fn get_stats(&self) -> ProfilerStats {
let call_count = self.call_count.load(Ordering::Relaxed);
let total_time = self.total_time.load(Ordering::Relaxed);
ProfilerStats {
name: self.name.clone(),
call_count,
total_time,
average_time: if call_count > 0 {
total_time / call_count
} else {
0
},
min_time: if call_count > 0 {
self.min_time.load(Ordering::Relaxed)
} else {
0
},
max_time: self.max_time.load(Ordering::Relaxed),
}
}
pub fn reset(&self) {
self.call_count.store(0, Ordering::Relaxed);
self.total_time.store(0, Ordering::Relaxed);
self.min_time.store(u64::MAX, Ordering::Relaxed);
self.max_time.store(0, Ordering::Relaxed);
}
}
/// Profiler statistics snapshot
#[derive(Debug, Clone)]
pub struct ProfilerStats {
pub name: String,
pub call_count: u64,
pub total_time: u64,
pub average_time: u64,
pub min_time: u64,
pub max_time: u64,
}
/// System-wide performance monitoring
pub struct PerformanceMonitor {
counters: Spinlock<BTreeMap<CounterType, PerformanceCounter>>,
profilers: Spinlock<BTreeMap<String, Profiler>>,
events: Spinlock<Vec<PerformanceEvent>>,
max_events: usize,
monitoring_enabled: AtomicBool,
}
impl PerformanceMonitor {
pub const fn new() -> Self {
Self {
counters: Spinlock::new(BTreeMap::new()),
profilers: Spinlock::new(BTreeMap::new()),
events: Spinlock::new(Vec::new()),
max_events: 10000,
monitoring_enabled: AtomicBool::new(true),
}
}
/// Initialize default performance counters
pub fn init(&self) -> Result<()> {
let mut counters = self.counters.lock();
counters.insert(
CounterType::ContextSwitches,
PerformanceCounter::new(
CounterType::ContextSwitches,
"Context switches".to_string(),
),
);
counters.insert(
CounterType::SystemCalls,
PerformanceCounter::new(
CounterType::SystemCalls,
"System calls".to_string(),
),
);
counters.insert(
CounterType::Interrupts,
PerformanceCounter::new(
CounterType::Interrupts,
"Hardware interrupts".to_string(),
),
);
counters.insert(
CounterType::MemoryAllocations,
PerformanceCounter::new(
CounterType::MemoryAllocations,
"Memory allocations".to_string(),
),
);
counters.insert(
CounterType::PageFaults,
PerformanceCounter::new(CounterType::PageFaults, "Page faults".to_string()),
);
drop(counters);
crate::info!("Performance monitoring initialized");
Ok(())
}
/// Record performance event
pub fn record_event(&self, counter_type: CounterType, value: u64) {
if !self.monitoring_enabled.load(Ordering::Relaxed) {
return;
}
// Update counter
if let Some(counter) = self.counters.lock().get(&counter_type) {
counter.increment(value);
}
// Record event
let event = PerformanceEvent {
counter_type,
value,
timestamp: crate::time::get_jiffies(),
process_id: None, // TODO: Get current process ID
thread_id: None, // TODO: Get current thread ID
cpu_id: None, // TODO: Get current CPU ID
};
let mut events = self.events.lock();
if events.len() >= self.max_events {
events.remove(0); // Remove oldest event
}
events.push(event);
}
/// Get performance counter value
pub fn get_counter(&self, counter_type: CounterType) -> Option<u64> {
self.counters
.lock()
.get(&counter_type)
.map(|c| c.get_value())
}
/// Reset performance counter
pub fn reset_counter(&self, counter_type: CounterType) -> Result<()> {
match self.counters.lock().get(&counter_type) {
Some(counter) => {
counter.reset();
Ok(())
}
None => Err(Error::NotFound),
}
}
/// Create or get profiler
pub fn get_profiler(&self, name: String) -> Result<()> {
let mut profilers = self.profilers.lock();
if !profilers.contains_key(&name) {
profilers.insert(name.clone(), Profiler::new(name));
}
Ok(())
}
/// Record profiler execution
pub fn record_profiler(&self, name: &str, duration: u64) -> Result<()> {
match self.profilers.lock().get(name) {
Some(profiler) => {
profiler.record_execution(duration);
Ok(())
}
None => Err(Error::NotFound),
}
}
/// Get all profiler statistics
pub fn get_profiler_stats(&self) -> Vec<ProfilerStats> {
self.profilers
.lock()
.values()
.map(|p| p.get_stats())
.collect()
}
/// Get performance summary
pub fn get_summary(&self) -> PerformanceSummary {
let counters = self.counters.lock();
let counter_values: Vec<_> =
counters.iter().map(|(t, c)| (*t, c.get_value())).collect();
drop(counters);
let profiler_stats = self.get_profiler_stats();
let event_count = self.events.lock().len();
PerformanceSummary {
counters: counter_values,
profilers: profiler_stats,
total_events: event_count,
monitoring_enabled: self.monitoring_enabled.load(Ordering::Relaxed),
}
}
/// Enable/disable monitoring
pub fn set_monitoring(&self, enabled: bool) {
self.monitoring_enabled.store(enabled, Ordering::Relaxed);
}
/// Clear all events
pub fn clear_events(&self) {
self.events.lock().clear();
}
/// Reset all counters and profilers
pub fn reset_all(&self) {
for counter in self.counters.lock().values() {
counter.reset();
}
for profiler in self.profilers.lock().values() {
profiler.reset();
}
self.clear_events();
}
}
/// Performance summary structure
#[derive(Debug, Clone)]
pub struct PerformanceSummary {
pub counters: Vec<(CounterType, u64)>,
pub profilers: Vec<ProfilerStats>,
pub total_events: usize,
pub monitoring_enabled: bool,
}
/// RAII profiler guard for automatic timing
pub struct ProfileGuard {
profiler_name: String,
start_time: u64,
}
impl ProfileGuard {
pub fn new(profiler_name: String) -> Result<Self> {
// Ensure profiler exists
PERFORMANCE_MONITOR.get_profiler(profiler_name.clone())?;
Ok(Self {
profiler_name,
start_time: crate::time::get_jiffies().0,
})
}
}
impl Drop for ProfileGuard {
fn drop(&mut self) {
let end_time = crate::time::get_jiffies().0;
let duration = end_time.saturating_sub(self.start_time);
let _ = PERFORMANCE_MONITOR.record_profiler(&self.profiler_name, duration);
}
}
/// Global performance monitor
static PERFORMANCE_MONITOR: PerformanceMonitor = PerformanceMonitor::new();
/// Initialize performance monitoring
pub fn init_performance_monitoring() -> Result<()> {
PERFORMANCE_MONITOR.init()
}
/// Record performance event
pub fn record_event(counter_type: CounterType, value: u64) {
PERFORMANCE_MONITOR.record_event(counter_type, value);
}
/// Get performance counter value
pub fn get_counter(counter_type: CounterType) -> Option<u64> {
PERFORMANCE_MONITOR.get_counter(counter_type)
}
/// Reset performance counter
pub fn reset_counter(counter_type: CounterType) -> Result<()> {
PERFORMANCE_MONITOR.reset_counter(counter_type)
}
/// Create profiler guard for automatic timing
pub fn profile(name: String) -> Result<ProfileGuard> {
ProfileGuard::new(name)
}
/// Get performance summary
pub fn get_performance_summary() -> PerformanceSummary {
PERFORMANCE_MONITOR.get_summary()
}
/// Enable/disable performance monitoring
pub fn set_monitoring_enabled(enabled: bool) {
PERFORMANCE_MONITOR.set_monitoring(enabled);
}
/// Clear performance events
pub fn clear_performance_events() {
PERFORMANCE_MONITOR.clear_events();
}
/// Reset all performance data
pub fn reset_all_performance_data() {
PERFORMANCE_MONITOR.reset_all();
}
/// Profile function execution (returns RAII guard)
pub fn profile_function(function_name: &str) -> Result<ProfileGuard> {
profile(function_name.to_string())
}
/// Convenience macros for performance monitoring
#[macro_export]
macro_rules! perf_counter {
($counter_type:expr, $value:expr) => {
$crate::advanced_perf::record_event($counter_type, $value);
};
}
#[macro_export]
macro_rules! perf_profile {
($name:expr, $code:block) => {{
let _guard = $crate::advanced_perf::profile($name.to_string());
$code
}};
}

13
kernel/src/arch/mod.rs Archivo normal
Ver fichero

@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
//! Architecture-specific code
#[cfg(target_arch = "x86_64")]
pub mod x86_64;
// Other architectures can be added here when needed
// #[cfg(target_arch = "aarch64")]
// pub mod aarch64;
// #[cfg(target_arch = "riscv64")]
// pub mod riscv64;

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

@@ -0,0 +1,296 @@
# SPDX-License-Identifier: GPL-2.0
# Rust Kernel boot entry point for x86_64
.section .multiboot_header, "a"
# Multiboot 1 Header
.align 4
.long 0x1BADB002 # magic
.long 0x00000003 # flags (align + meminfo)
.long -(0x1BADB002 + 0x00000003) # checksum
# Multiboot 2 Header
.align 8
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
multiboot_info_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_pml4
boot_pml4:
.skip 4096
.global boot_pdp
boot_pdp:
.skip 4096
.global boot_pd
boot_pd:
.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
gdt64.pointer:
.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 or clobber EAX
movl %eax, multiboot_magic_store
movl %ebx, multiboot_info_store
# Restore magic for check (or use stored value)
movl multiboot_magic_store, %eax
# Check for multiboot
cmpl $0x36d76289, %eax
je .multiboot_ok
cmpl $0x2BADB002, %eax
je .multiboot_ok
jmp no_multiboot
.multiboot_ok:
# 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_pml4, %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
setne %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
setnz %al
movzbl %al, %eax
ret
.no_long_mode:
xorl %eax, %eax
ret
setup_page_tables:
# Map PML4[0] -> PDP
movl $boot_pdp, %eax
orl $0b11, %eax # present + writable
movl %eax, boot_pml4
# Map PDP[0] -> PD
movl $boot_pd, %eax
orl $0b11, %eax # present + writable
movl %eax, boot_pdp
# Map PD[0..511] -> 2MB Pages (Identity map 0-1GB)
movl $boot_pd, %edi
movl $0, %ebx # Physical address
movl $512, %ecx # 512 entries
.map_pd_loop:
movl %ebx, %eax
orl $0b10000011, %eax # present + writable + huge (2MB)
movl %eax, (%edi)
addl $8, %edi # Next entry
addl $0x200000, %ebx # Next 2MB
loop .map_pd_loop
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:
# DEBUG: Print 'M' to serial port COM1
mov $0x3f8, %dx
mov $'M', %al
out %al, %dx
movl $no_multiboot_msg, %esi
call print_string_32
jmp halt32
no_cpuid:
movl $no_cpuid_msg, %esi
call print_string_32
jmp halt32
no_long_mode:
movl $no_long_mode_msg, %esi
call print_string_32
jmp halt32
# 32-bit string printing
print_string_32:
movl $0xb8000, %edi
movb $0x4f, %ah # White on red
.print_loop_32:
lodsb
testb %al, %al
jz .print_done_32
stosw
jmp .print_loop_32
.print_done_32:
ret
halt32:
cli
hlt
jmp halt32
.section .rodata
boot_msg:
.asciz "Rust Kernel booting..."
no_multiboot_msg:
.asciz "ERROR: Not loaded by multiboot bootloader"
no_cpuid_msg:
.asciz "ERROR: CPUID not supported"
no_long_mode_msg:
.asciz "ERROR: Long mode not supported"

Ver fichero

@@ -0,0 +1,294 @@
// SPDX-License-Identifier: GPL-2.0
//! Context switching for x86_64
use core::arch::asm;
/// CPU context for x86_64
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Context {
// General purpose registers
pub rax: u64,
pub rbx: u64,
pub rcx: u64,
pub rdx: u64,
pub rsi: u64,
pub rdi: u64,
pub rbp: u64,
pub rsp: u64,
pub r8: u64,
pub r9: u64,
pub r10: u64,
pub r11: u64,
pub r12: u64,
pub r13: u64,
pub r14: u64,
pub r15: u64,
// Control registers
pub rip: u64,
pub rflags: u64,
pub cr3: u64, // Page table base
// Segment selectors
pub cs: u16,
pub ds: u16,
pub es: u16,
pub fs: u16,
pub gs: u16,
pub ss: u16,
// FPU state (simplified)
pub fpu_state: [u8; 512], // FXSAVE area
}
impl Context {
pub fn new() -> Self {
Self {
rax: 0,
rbx: 0,
rcx: 0,
rdx: 0,
rsi: 0,
rdi: 0,
rbp: 0,
rsp: 0,
r8: 0,
r9: 0,
r10: 0,
r11: 0,
r12: 0,
r13: 0,
r14: 0,
r15: 0,
rip: 0,
rflags: 0x200, // Enable interrupts
cr3: 0,
cs: 0x08, // Kernel code segment
ds: 0x10,
es: 0x10,
fs: 0x10,
gs: 0x10,
ss: 0x10, // Kernel data segment
fpu_state: [0; 512],
}
}
/// Create a new kernel context
pub fn new_kernel(entry_point: u64, stack_ptr: u64, page_table: u64) -> Self {
let mut ctx = Self::new();
ctx.rip = entry_point;
ctx.rsp = stack_ptr;
ctx.cr3 = page_table;
ctx
}
/// Create a new user context
pub fn new_user(entry_point: u64, stack_ptr: u64, page_table: u64) -> Self {
let mut ctx = Self::new();
ctx.rip = entry_point;
ctx.rsp = stack_ptr;
ctx.cr3 = page_table;
ctx.cs = 0x18 | 3; // User code segment with RPL=3
ctx.ds = 0x20 | 3; // User data segment with RPL=3
ctx.es = 0x20 | 3;
ctx.fs = 0x20 | 3;
ctx.gs = 0x20 | 3;
ctx.ss = 0x20 | 3;
ctx.rflags |= 0x200; // Enable interrupts in user mode
ctx
}
/// Save current CPU context
pub fn save_current(&mut self) {
unsafe {
// Save registers in smaller groups to avoid register pressure
asm!(
"mov {}, rax",
"mov {}, rbx",
"mov {}, rcx",
"mov {}, rdx",
out(reg) self.rax,
out(reg) self.rbx,
out(reg) self.rcx,
out(reg) self.rdx,
);
asm!(
"mov {}, rsi",
"mov {}, rdi",
"mov {}, rbp",
"mov {}, rsp",
out(reg) self.rsi,
out(reg) self.rdi,
out(reg) self.rbp,
out(reg) self.rsp,
);
asm!(
"mov {}, r8",
"mov {}, r9",
"mov {}, r10",
"mov {}, r11",
out(reg) self.r8,
out(reg) self.r9,
out(reg) self.r10,
out(reg) self.r11,
);
asm!(
"mov {}, r12",
"mov {}, r13",
"mov {}, r14",
"mov {}, r15",
out(reg) self.r12,
out(reg) self.r13,
out(reg) self.r14,
out(reg) self.r15,
);
// Save flags
asm!("pushfq; pop {}", out(reg) self.rflags);
// Save CR3 (page table)
asm!("mov {}, cr3", out(reg) self.cr3);
// Save segment registers
asm!("mov {0:x}, cs", out(reg) self.cs);
asm!("mov {0:x}, ds", out(reg) self.ds);
asm!("mov {0:x}, es", out(reg) self.es);
asm!("mov {0:x}, fs", out(reg) self.fs);
asm!("mov {0:x}, gs", out(reg) self.gs);
asm!("mov {0:x}, ss", out(reg) self.ss);
}
}
/// Restore CPU context and switch to it
pub unsafe fn restore(&self) -> ! {
// Restore context using the pointer to self (passed in rdi)
asm!(
// Restore CR3 (Page Table)
"mov rax, [rdi + 144]",
"mov cr3, rax",
// Switch stack to the target stack
"mov rsp, [rdi + 56]",
// Construct interrupt stack frame for iretq
// Stack layout: SS, RSP, RFLAGS, CS, RIP
// SS
"movzx rax, word ptr [rdi + 162]",
"push rax",
// RSP (target stack pointer)
"mov rax, [rdi + 56]",
"push rax",
// RFLAGS
"mov rax, [rdi + 136]",
"push rax",
// CS
"movzx rax, word ptr [rdi + 152]",
"push rax",
// RIP
"mov rax, [rdi + 128]",
"push rax",
// Push General Purpose Registers onto the new stack
// We push them in reverse order of popping
"push qword ptr [rdi + 0]", // rax
"push qword ptr [rdi + 8]", // rbx
"push qword ptr [rdi + 16]", // rcx
"push qword ptr [rdi + 24]", // rdx
"push qword ptr [rdi + 32]", // rsi
"push qword ptr [rdi + 40]", // rdi
"push qword ptr [rdi + 48]", // rbp
// rsp is handled by stack switch
"push qword ptr [rdi + 64]", // r8
"push qword ptr [rdi + 72]", // r9
"push qword ptr [rdi + 80]", // r10
"push qword ptr [rdi + 88]", // r11
"push qword ptr [rdi + 96]", // r12
"push qword ptr [rdi + 104]", // r13
"push qword ptr [rdi + 112]", // r14
"push qword ptr [rdi + 120]", // r15
// Restore Segment Registers
"mov ax, [rdi + 154]", // ds
"mov ds, ax",
"mov ax, [rdi + 156]", // es
"mov es, ax",
"mov ax, [rdi + 158]", // fs
"mov fs, ax",
"mov ax, [rdi + 160]", // gs
"mov gs, ax",
// Pop General Purpose Registers
"pop r15",
"pop r14",
"pop r13",
"pop r12",
"pop r11",
"pop r10",
"pop r9",
"pop r8",
"pop rbp",
"pop rdi", // This restores the target rdi
"pop rsi",
"pop rdx",
"pop rcx",
"pop rbx",
"pop rax",
// Return from interrupt (restores RIP, CS, RFLAGS, RSP, SS)
"iretq",
in("rdi") self,
options(noreturn)
);
}
}
/// Context switch from old context to new context
pub unsafe fn switch_context(old_ctx: &mut Context, new_ctx: &Context) {
// Save current context
old_ctx.save_current();
// Restore new context
new_ctx.restore();
}
/// Get current stack pointer
pub fn get_current_stack_pointer() -> u64 {
let rsp: u64;
unsafe {
asm!("mov {}, rsp", out(reg) rsp);
}
rsp
}
/// Get current instruction pointer (return address)
pub fn get_current_instruction_pointer() -> u64 {
let rip: u64;
unsafe {
asm!("lea {}, [rip]", out(reg) rip);
}
rip
}
/// Save FPU state
pub fn save_fpu_state(buffer: &mut [u8; 512]) {
unsafe {
asm!("fxsave [{}]", in(reg) buffer.as_mut_ptr());
}
}
/// Restore FPU state
pub fn restore_fpu_state(buffer: &[u8; 512]) {
unsafe {
asm!("fxrstor [{}]", in(reg) buffer.as_ptr());
}
}

156
kernel/src/arch/x86_64/gdt.rs Archivo normal
Ver fichero

@@ -0,0 +1,156 @@
// SPDX-License-Identifier: GPL-2.0
//! 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)
);
}
}

1067
kernel/src/arch/x86_64/idt.rs Archivo normal

La diferencia del archivo ha sido suprimido porque es demasiado grande Cargar Diff

10
kernel/src/arch/x86_64/mod.rs Archivo normal
Ver fichero

@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
//! x86_64 architecture support
pub mod context;
pub mod gdt;
pub mod idt;
pub mod paging;
pub mod pic;
pub mod port;

Ver fichero

@@ -0,0 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
//! Paging stub
pub fn init() {}

89
kernel/src/arch/x86_64/pic.rs Archivo normal
Ver fichero

@@ -0,0 +1,89 @@
// SPDX-License-Identifier: GPL-2.0
//! Programmable Interrupt Controller (8259 PIC) support
use crate::arch::x86_64::port::Port;
/// Primary PIC ports
const PIC1_COMMAND: u16 = 0x20;
const PIC1_DATA: u16 = 0x21;
/// Secondary PIC ports
const PIC2_COMMAND: u16 = 0xA0;
const PIC2_DATA: u16 = 0xA1;
/// PIC commands
const PIC_EOI: u8 = 0x20; // End of Interrupt
/// Initialize the PIC
pub unsafe fn init_pic() {
let mut pic1_command = Port::new(PIC1_COMMAND);
let mut pic1_data = Port::new(PIC1_DATA);
let mut pic2_command = Port::new(PIC2_COMMAND);
let mut pic2_data = Port::new(PIC2_DATA);
// Save masks
let mask1 = pic1_data.read() as u8;
let mask2 = pic2_data.read() as u8;
// Initialize PIC1
pic1_command.write(0x11); // ICW1: Initialize + expect ICW4
io_wait();
pic1_data.write(0x20); // ICW2: PIC1 offset (32)
io_wait();
pic1_data.write(0x04); // ICW3: Tell PIC1 there's a PIC2 at IRQ2
io_wait();
pic1_data.write(0x01); // ICW4: 8086 mode
io_wait();
// Initialize PIC2
pic2_command.write(0x11); // ICW1: Initialize + expect ICW4
io_wait();
pic2_data.write(0x28); // ICW2: PIC2 offset (40)
io_wait();
pic2_data.write(0x02); // ICW3: Tell PIC2 it's at IRQ2 of PIC1
io_wait();
pic2_data.write(0x01); // ICW4: 8086 mode
io_wait();
// Restore masks
pic1_data.write(mask1 as u32);
pic2_data.write(mask2 as u32);
}
/// Send End of Interrupt signal
pub unsafe fn send_eoi(irq: u8) {
let mut pic1_command = Port::new(PIC1_COMMAND);
let mut pic2_command = Port::new(PIC2_COMMAND);
if irq >= 8 {
pic2_command.write(PIC_EOI as u32);
}
pic1_command.write(PIC_EOI as u32);
}
/// Mask (disable) an IRQ
pub unsafe fn mask_irq(irq: u8) {
let port = if irq < 8 { PIC1_DATA } else { PIC2_DATA };
let mut data_port = Port::new(port);
let value = data_port.read() as u8;
let mask = 1 << (irq % 8);
data_port.write((value | mask) as u32);
}
/// Unmask (enable) an IRQ
pub unsafe fn unmask_irq(irq: u8) {
let port = if irq < 8 { PIC1_DATA } else { PIC2_DATA };
let mut data_port = Port::new(port);
let value = data_port.read() as u8;
let mask = 1 << (irq % 8);
data_port.write((value & !mask) as u32);
}
/// I/O wait - small delay for old hardware
unsafe fn io_wait() {
let mut port = Port::new(0x80);
port.write(0);
}

78
kernel/src/arch/x86_64/port.rs Archivo normal
Ver fichero

@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0
//! Port I/O operations
use core::arch::asm;
/// Port I/O wrapper
pub struct Port {
port: u16,
}
impl Port {
pub const fn new(port: u16) -> Self {
Self { port }
}
pub unsafe fn write(&mut self, value: u32) {
asm!(
"out dx, eax",
in("dx") self.port,
in("eax") value,
);
}
pub unsafe fn read(&mut self) -> u32 {
let value: u32;
asm!(
"in eax, dx",
out("eax") value,
in("dx") self.port,
);
value
}
}
/// Read a byte from a port
pub unsafe fn inb(port: u16) -> u8 {
let value: u8;
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) {
asm!(
"out dx, al",
in("dx") port,
in("al") value,
options(nomem, nostack, preserves_flags)
);
}
/// Output a 32-bit value to a port
pub unsafe fn outl(port: u16, value: u32) {
asm!(
"out dx, eax",
in("dx") port,
in("eax") value,
options(nostack, preserves_flags)
);
}
/// Input a 32-bit value from a port
pub unsafe fn inl(port: u16) -> u32 {
let value: u32;
asm!(
"in eax, dx",
in("dx") port,
out("eax") value,
options(nostack, preserves_flags)
);
value
}

97
kernel/src/arp.rs Archivo normal
Ver fichero

@@ -0,0 +1,97 @@
// SPDX-License-Identifier: GPL-2.0
//! ARP (Address Resolution Protocol) implementation.
use crate::error::{Error, Result};
use crate::network::{Ipv4Address, MacAddress};
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ArpOperation {
Request = 1,
Reply = 2,
}
#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
pub struct ArpPacket {
pub htype: [u8; 2],
pub ptype: [u8; 2],
pub hlen: u8,
pub plen: u8,
pub oper: [u8; 2],
pub sha: MacAddress,
pub spa: Ipv4Address,
pub tha: MacAddress,
pub tpa: Ipv4Address,
}
impl ArpPacket {
pub fn new(
oper: ArpOperation,
sha: MacAddress,
spa: Ipv4Address,
tha: MacAddress,
tpa: Ipv4Address,
) -> Self {
Self {
htype: (1 as u16).to_be_bytes(), // Ethernet
ptype: (0x0800 as u16).to_be_bytes(), // IPv4
hlen: 6,
plen: 4,
oper: (oper as u16).to_be_bytes(),
sha,
spa,
tha,
tpa,
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::with_capacity(28);
bytes.extend_from_slice(&self.htype);
bytes.extend_from_slice(&self.ptype);
bytes.push(self.hlen);
bytes.push(self.plen);
bytes.extend_from_slice(&self.oper);
bytes.extend_from_slice(self.sha.bytes());
bytes.extend_from_slice(self.spa.bytes());
bytes.extend_from_slice(self.tha.bytes());
bytes.extend_from_slice(self.tpa.bytes());
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() < 28 {
return Err(Error::InvalidArgument);
}
let mut htype = [0u8; 2];
htype.copy_from_slice(&bytes[0..2]);
let mut ptype = [0u8; 2];
ptype.copy_from_slice(&bytes[2..4]);
let hlen = bytes[4];
let plen = bytes[5];
let mut oper = [0u8; 2];
oper.copy_from_slice(&bytes[6..8]);
let mut sha_bytes = [0u8; 6];
sha_bytes.copy_from_slice(&bytes[8..14]);
let mut spa_bytes = [0u8; 4];
spa_bytes.copy_from_slice(&bytes[14..18]);
let mut tha_bytes = [0u8; 6];
tha_bytes.copy_from_slice(&bytes[18..24]);
let mut tpa_bytes = [0u8; 4];
tpa_bytes.copy_from_slice(&bytes[24..28]);
Ok(Self {
htype,
ptype,
hlen,
plen,
oper,
sha: MacAddress::new(sha_bytes),
spa: Ipv4Address::from_bytes(spa_bytes),
tha: MacAddress::new(tha_bytes),
tpa: Ipv4Address::from_bytes(tpa_bytes),
})
}
}

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

@@ -0,0 +1,193 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel benchmark system
use alloc::{
string::{String, ToString},
vec,
vec::Vec,
};
use crate::error::Result;
use crate::time::{get_jiffies, monotonic_time};
use crate::{info, warn};
/// Benchmark result
#[derive(Debug, Clone)]
pub struct BenchmarkResult {
pub name: String,
pub iterations: u64,
pub total_time_ns: u64,
pub avg_time_ns: u64,
pub min_time_ns: u64,
pub max_time_ns: u64,
}
impl BenchmarkResult {
pub fn new(name: String, iterations: u64, times: &[u64]) -> Self {
let total_time_ns = times.iter().sum();
let avg_time_ns = total_time_ns / iterations;
let min_time_ns = *times.iter().min().unwrap_or(&0);
let max_time_ns = *times.iter().max().unwrap_or(&0);
Self {
name,
iterations,
total_time_ns,
avg_time_ns,
min_time_ns,
max_time_ns,
}
}
pub fn print(&self) {
info!("Benchmark: {}", self.name);
info!(" Iterations: {}", self.iterations);
info!(" Total time: {} ns", self.total_time_ns);
info!(" Average time: {} ns", self.avg_time_ns);
info!(" Min time: {} ns", self.min_time_ns);
info!(" Max time: {} ns", self.max_time_ns);
}
}
/// Benchmark function type
pub type BenchmarkFn = fn();
/// Run a benchmark
pub fn benchmark(name: &str, iterations: u64, func: BenchmarkFn) -> BenchmarkResult {
let mut times = Vec::new();
info!("Running benchmark: {} ({} iterations)", name, iterations);
for _i in 0..iterations {
let start = monotonic_time();
func();
let end = monotonic_time();
let elapsed_ns = (end.to_ns() as i64 - start.to_ns() as i64) as u64;
times.push(elapsed_ns);
}
let result = BenchmarkResult::new(name.to_string(), iterations, &times);
result.print();
result
}
/// Memory allocation benchmark
fn bench_memory_alloc() {
let _vec: Vec<u8> = Vec::with_capacity(1024);
}
/// Memory deallocation benchmark
fn bench_memory_dealloc() {
let vec: Vec<u8> = Vec::with_capacity(1024);
drop(vec);
}
/// Simple arithmetic benchmark
fn bench_arithmetic() {
let mut result = 0u64;
for i in 0..1000 {
result = result.wrapping_add(i).wrapping_mul(2);
}
// Prevent optimization
core::hint::black_box(result);
}
/// String operations benchmark
fn bench_string_ops() {
let mut s = String::new();
for i in 0..100 {
s.push_str("test");
s.push((b'0' + (i % 10) as u8) as char);
}
core::hint::black_box(s);
}
/// Interrupt enable/disable benchmark
fn bench_interrupt_toggle() {
crate::interrupt::disable();
crate::interrupt::enable();
}
/// Run all kernel benchmarks
pub fn run_all_benchmarks() -> Result<Vec<BenchmarkResult>> {
info!("Running kernel performance benchmarks");
let mut results = Vec::new();
// Memory benchmarks
results.push(benchmark("memory_alloc", 1000, bench_memory_alloc));
results.push(benchmark("memory_dealloc", 1000, bench_memory_dealloc));
// CPU benchmarks
results.push(benchmark("arithmetic", 100, bench_arithmetic));
results.push(benchmark("string_ops", 100, bench_string_ops));
// System call benchmarks
results.push(benchmark("interrupt_toggle", 1000, bench_interrupt_toggle));
info!("Benchmark suite completed");
Ok(results)
}
/// Run specific benchmark
pub fn run_benchmark(name: &str, iterations: u64) -> Result<BenchmarkResult> {
match name {
"memory_alloc" => Ok(benchmark(name, iterations, bench_memory_alloc)),
"memory_dealloc" => Ok(benchmark(name, iterations, bench_memory_dealloc)),
"arithmetic" => Ok(benchmark(name, iterations, bench_arithmetic)),
"string_ops" => Ok(benchmark(name, iterations, bench_string_ops)),
"interrupt_toggle" => Ok(benchmark(name, iterations, bench_interrupt_toggle)),
_ => {
warn!("Unknown benchmark: {}", name);
Err(crate::error::Error::NotFound)
}
}
}
/// Get available benchmarks
pub fn list_benchmarks() -> Vec<&'static str> {
vec![
"memory_alloc",
"memory_dealloc",
"arithmetic",
"string_ops",
"interrupt_toggle",
]
}
/// Performance stress test
pub fn stress_test(duration_seconds: u64) -> Result<()> {
info!("Running stress test for {} seconds", duration_seconds);
let start_jiffies = get_jiffies();
let target_jiffies = start_jiffies.0 + (duration_seconds * crate::time::HZ);
let mut iterations = 0u64;
while get_jiffies().0 < target_jiffies {
// Mix of different operations
bench_arithmetic();
bench_memory_alloc();
bench_string_ops();
bench_interrupt_toggle();
iterations += 1;
// Yield occasionally to prevent monopolizing CPU
if iterations % 1000 == 0 {
crate::kthread::kthread_yield();
}
}
let elapsed_jiffies = get_jiffies().0 - start_jiffies.0;
let ops_per_second = (iterations * crate::time::HZ) / elapsed_jiffies;
info!("Stress test completed:");
info!(" Duration: {} jiffies", elapsed_jiffies);
info!(" Total iterations: {}", iterations);
info!(" Operations per second: {}", ops_per_second);
Ok(())
}

345
kernel/src/boot.rs Archivo normal
Ver fichero

@@ -0,0 +1,345 @@
// SPDX-License-Identifier: GPL-2.0
//! Boot process and hardware initialization
use alloc::string::ToString;
use crate::error::Result;
use crate::{error, info};
/// 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::error::Result;
use crate::info;
use crate::types::{PhysAddr, VirtAddr};
/// 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: [MemoryMapEntry; 32],
pub region_count: usize,
}
impl BootMemoryInfo {
pub fn new() -> Self {
Self {
total_memory: 0,
available_memory: 0,
memory_regions: [MemoryMapEntry {
base_addr: 0,
length: 0,
type_: 0,
reserved: 0,
}; 32],
region_count: 0,
}
}
pub fn add_region(&mut self, entry: MemoryMapEntry) {
if entry.type_ == memory_type::AVAILABLE {
self.available_memory += entry.length;
}
self.total_memory += entry.length;
if self.region_count < 32 {
self.memory_regions[self.region_count] = entry;
self.region_count += 1;
}
}
}
/// Parse multiboot2 information and initialize memory management
pub fn init_memory_from_multiboot(multiboot_addr: usize) -> Result<()> {
crate::console::write_str("Parsing multiboot\n");
// Validate multiboot address is in identity-mapped range (0-1GB)
if multiboot_addr >= 0x40000000 {
// 1GB
crate::console::write_str("ERROR: multiboot addr out of range\n");
return Err(crate::error::Error::InvalidArgument);
}
crate::console::write_str("Multiboot addr validated\n");
let multiboot_info = unsafe { &*(multiboot_addr as *const MultibootInfo) };
crate::console::write_str("Got multiboot info\n");
// Parse memory map from multiboot info
let mut memory_info = BootMemoryInfo::new();
crate::console::write_str("Created BootMemoryInfo\n");
// 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,
};
crate::console::write_str("Adding default memory region\n");
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
// Note: Only first 1GB is identity-mapped in boot.s
const MAX_IDENTITY_MAPPED: u64 = 1024 * 1024 * 1024; // 1GB
crate::console::write_str("Processing memory regions\n");
for i in 0..memory_info.region_count {
crate::console::write_str("Region loop iteration\n");
let region = &memory_info.memory_regions[i];
if region.type_ == memory_type::AVAILABLE {
let start_addr = region.base_addr;
let end_addr = region.base_addr + region.length;
crate::console::write_str("Available region found\n");
// Clamp to identity-mapped region
let safe_start = start_addr.max(0x100000); // Skip first 1MB (BIOS/kernel)
let safe_end = end_addr.min(MAX_IDENTITY_MAPPED);
crate::console::write_str("Clamped region\n");
if safe_start >= safe_end {
crate::console::write_str("Skipping invalid range\n");
continue; // Skip invalid/unmapped region
}
crate::console::write_str("About to call add_free_range\n");
// Add this memory region to the page allocator
crate::memory::page::add_free_range(
PhysAddr::new(safe_start as usize),
PhysAddr::new(safe_end as usize),
)?;
crate::console::write_str("Successfully added free range\n");
}
}
crate::console::write_str("Memory init completed\n");
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(())
}
/// Initialize multiboot information
/// This should be called at the very beginning of kernel execution
pub fn multiboot_init() {
// Parse multiboot information from bootloader
// For now, we'll use a combination of detection and defaults
let detected_memory = detect_memory_size();
let cpu_count = detect_cpu_count();
unsafe {
BOOT_INFO = BootInfo {
memory_size: detected_memory,
available_memory: (detected_memory * 95) / 100, // 95% available
cpu_count,
boot_time: read_tsc(),
command_line: None,
initrd_start: None,
initrd_size: None,
multiboot_addr: None,
};
}
info!("Multiboot information initialized");
info!(" Memory size: {} MB", detected_memory / (1024 * 1024));
info!(
" Available memory: {} MB",
get_boot_info().available_memory / (1024 * 1024)
);
info!(" CPU count: {}", cpu_count);
}
/// Detect total system memory
fn detect_memory_size() -> usize {
// Use CMOS to get basic memory information
unsafe {
// Read extended memory from CMOS (simplified)
crate::arch::x86_64::port::outb(0x70, 0x17);
let low = crate::arch::x86_64::port::inb(0x71) as usize;
crate::arch::x86_64::port::outb(0x70, 0x18);
let high = crate::arch::x86_64::port::inb(0x71) as usize;
let extended_mem = (high << 8) | low; // in KB
let total_mem = 1024 * 1024 + (extended_mem * 1024); // Base 1MB + extended
// Reasonable bounds checking
if total_mem < 16 * 1024 * 1024 {
// Default to 64MB if detection seems wrong
64 * 1024 * 1024
} else if total_mem > 8 * 1024 * 1024 * 1024 {
// Cap at 8GB for safety
8 * 1024 * 1024 * 1024
} else {
total_mem
}
}
}
/// Detect CPU count (simplified)
fn detect_cpu_count() -> usize {
// For now, assume single CPU
// In a real implementation, this would parse ACPI tables or use CPUID
1
}
/// Read Time Stamp Counter
fn read_tsc() -> u64 {
unsafe {
let low: u32;
let high: u32;
core::arch::asm!(
"rdtsc",
out("eax") low,
out("edx") high,
options(nomem, nostack, preserves_flags)
);
((high as u64) << 32) | (low as u64)
}
}

283
kernel/src/console.rs Archivo normal
Ver fichero

@@ -0,0 +1,283 @@
// SPDX-License-Identifier: GPL-2.0
//! Console and kernel output
use core::fmt::{self, Write};
use crate::error::Result;
use crate::sync::Spinlock;
/// Console writer
static CONSOLE: Spinlock<Console> = Spinlock::new(Console::new());
/// VGA text mode colors
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Color {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
LightGray = 7,
DarkGray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
Pink = 13,
Yellow = 14,
White = 15,
}
/// VGA text mode color code combining foreground and background colors
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
struct ColorCode(u8);
impl ColorCode {
const fn new(foreground: Color, background: Color) -> ColorCode {
ColorCode((background as u8) << 4 | (foreground as u8))
}
}
/// VGA text mode screen character
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
struct ScreenChar {
ascii_character: u8,
color_code: ColorCode,
}
/// VGA text mode buffer dimensions
const BUFFER_HEIGHT: usize = 25;
const BUFFER_WIDTH: usize = 80;
/// VGA text mode buffer structure
#[repr(transparent)]
struct Buffer {
chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
struct Console {
initialized: bool,
vga_buffer: Option<&'static mut Buffer>,
column_position: usize,
color_code: ColorCode,
}
impl Console {
const fn new() -> Self {
Self {
initialized: false,
vga_buffer: None,
column_position: 0,
color_code: ColorCode::new(Color::Yellow, Color::Black),
}
}
fn init(&mut self) -> Result<()> {
// Initialize VGA text mode buffer
self.vga_buffer = Some(unsafe { &mut *(0xb8000 as *mut Buffer) });
// Initialize serial port (COM1)
self.init_serial();
self.clear_screen();
self.initialized = true;
Ok(())
}
fn init_serial(&self) {
unsafe {
// Disable interrupts
core::arch::asm!("out dx, al", in("dx") 0x3F9u16, in("al") 0x00u8);
// Set baud rate divisor
core::arch::asm!("out dx, al", in("dx") 0x3FBu16, in("al") 0x80u8); // Enable DLAB
core::arch::asm!("out dx, al", in("dx") 0x3F8u16, in("al") 0x03u8); // Divisor low byte (38400 baud)
core::arch::asm!("out dx, al", in("dx") 0x3F9u16, in("al") 0x00u8); // Divisor high byte
// Configure line
core::arch::asm!("out dx, al", in("dx") 0x3FBu16, in("al") 0x03u8); // 8 bits, no parity, one stop bit
core::arch::asm!("out dx, al", in("dx") 0x3FCu16, in("al") 0xC7u8); // Enable FIFO, clear, 14-byte threshold
core::arch::asm!("out dx, al", in("dx") 0x3FEu16, in("al") 0x0Bu8); // IRQs enabled, RTS/DSR set
}
}
fn clear_screen(&mut self) {
if let Some(ref mut buffer) = self.vga_buffer {
let blank = ScreenChar {
ascii_character: b' ',
color_code: self.color_code,
};
for row in 0..BUFFER_HEIGHT {
for col in 0..BUFFER_WIDTH {
unsafe {
core::ptr::write_volatile(
&mut buffer.chars[row][col]
as *mut ScreenChar,
blank,
);
}
}
}
}
self.column_position = 0;
}
pub fn write_str(&mut self, s: &str) {
if !self.initialized {
return;
}
for byte in s.bytes() {
match byte {
b'\n' => self.new_line(),
byte => {
self.write_byte(byte);
}
}
}
}
fn write_byte(&mut self, byte: u8) {
// Write to serial port
self.write_serial(byte);
// Write to VGA buffer
match byte {
b'\n' => self.new_line(),
byte => {
if self.column_position >= BUFFER_WIDTH {
self.new_line();
}
if let Some(ref mut buffer) = self.vga_buffer {
let row = BUFFER_HEIGHT - 1;
let col = self.column_position;
let color_code = self.color_code;
unsafe {
core::ptr::write_volatile(
&mut buffer.chars[row][col]
as *mut ScreenChar,
ScreenChar {
ascii_character: byte,
color_code,
},
);
}
}
self.column_position += 1;
}
}
}
fn write_serial(&self, byte: u8) {
unsafe {
// Wait for transmit holding register to be empty
loop {
let mut status: u8;
core::arch::asm!("in al, dx", out("al") status, in("dx") 0x3FDu16);
if (status & 0x20) != 0 {
break;
}
}
// Write byte to serial port
core::arch::asm!(
"out dx, al",
in("dx") 0x3F8u16,
in("al") byte,
);
}
}
fn new_line(&mut self) {
if let Some(ref mut buffer) = self.vga_buffer {
// Scroll up
for row in 1..BUFFER_HEIGHT {
for col in 0..BUFFER_WIDTH {
unsafe {
let character = core::ptr::read_volatile(
&buffer.chars[row][col]
as *const ScreenChar,
);
core::ptr::write_volatile(
&mut buffer.chars[row - 1][col]
as *mut ScreenChar,
character,
);
}
}
}
// Clear bottom row
let blank = ScreenChar {
ascii_character: b' ',
color_code: self.color_code,
};
for col in 0..BUFFER_WIDTH {
unsafe {
core::ptr::write_volatile(
&mut buffer.chars[BUFFER_HEIGHT - 1][col]
as *mut ScreenChar,
blank,
);
}
}
}
self.column_position = 0;
}
}
/// Initialize console
pub fn init() -> Result<()> {
let mut console = CONSOLE.lock();
console.init()
}
/// Print function for kernel output
pub fn _print(args: fmt::Arguments) {
let mut console = CONSOLE.lock();
let mut writer = ConsoleWriter(&mut *console);
writer.write_fmt(args).unwrap();
}
/// Print function for kernel messages with prefix
pub fn _kprint(args: fmt::Arguments) {
let mut console = CONSOLE.lock();
let mut writer = ConsoleWriter(&mut *console);
writer.write_fmt(args).unwrap();
}
/// Print informational message
pub fn print_info(message: &str) {
let mut console = CONSOLE.lock();
let mut writer = ConsoleWriter(&mut *console);
writer.write_str("[INFO] ").unwrap();
writer.write_str(message).unwrap();
}
/// Write string to console
pub fn write_str(s: &str) {
let mut console = CONSOLE.lock();
console.write_str(s);
}
/// Clear the console screen
pub fn clear() {
let mut console = CONSOLE.lock();
console.clear_screen();
}
struct ConsoleWriter<'a>(&'a mut Console);
impl Write for ConsoleWriter<'_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.0.write_str(s);
Ok(())
}
}

8
kernel/src/cpu.rs Archivo normal
Ver fichero

@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
//! CPU management
use crate::error::Result;
pub fn init() -> Result<()> {
Ok(())
}

396
kernel/src/device.rs Archivo normal
Ver fichero

@@ -0,0 +1,396 @@
// SPDX-License-Identifier: GPL-2.0
//! Device management compatible with Linux kernel
use alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec};
use core::any::Any;
use crate::driver::Driver;
use crate::error::{Error, Result};
// Forward declarations for FileOperations trait
use crate::fs::{File as VfsFile, Inode as VfsInode};
use crate::memory::VmaArea;
use crate::sync::Spinlock;
/// Device number (major and minor) - Linux compatible
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct DeviceNumber {
pub major: u32,
pub minor: u32,
}
impl DeviceNumber {
/// Create a new device number
pub fn new(major: u32, minor: u32) -> Self {
Self { major, minor }
}
/// Convert to raw device number (Linux dev_t equivalent)
pub fn to_raw(&self) -> u64 {
((self.major as u64) << 32) | (self.minor as u64)
}
/// Alias for to_raw for compatibility
pub fn as_raw(&self) -> u64 {
self.to_raw()
}
/// Create from raw device number
pub fn from_raw(dev: u64) -> Self {
Self {
major: (dev >> 32) as u32,
minor: (dev & 0xFFFFFFFF) as u32,
}
}
}
/// Linux MKDEV macro equivalent
pub fn mkdev(major: u32, minor: u32) -> DeviceNumber {
DeviceNumber::new(major, minor)
}
/// Device types - Linux compatible
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeviceType {
Character,
Block,
Network,
Input,
Sound,
Video,
Misc,
Platform,
Pci,
Usb,
}
/// Device structure - similar to Linux struct device
#[derive(Debug)]
pub struct Device {
pub name: String,
pub device_type: DeviceType,
pub major: u32,
pub minor: u32,
pub driver: Option<Box<dyn Driver>>,
pub parent: Option<String>,
pub private_data: Option<Box<dyn Any + Send + Sync>>,
pub power_state: PowerState,
pub dma_coherent: bool,
pub numa_node: i32,
}
/// Device power states
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PowerState {
On,
Suspend,
Hibernate,
Off,
}
impl Device {
pub fn new(name: String, device_type: DeviceType, major: u32, minor: u32) -> Self {
Self {
name,
device_type,
major,
minor,
driver: None,
parent: None,
private_data: None,
power_state: PowerState::On,
dma_coherent: false,
numa_node: -1,
}
}
/// Set device driver
pub fn set_driver(&mut self, driver: Box<dyn Driver>) -> Result<()> {
// Probe the device with the driver
driver.probe(self)?;
self.driver = Some(driver);
Ok(())
}
/// Remove device driver
pub fn remove_driver(&mut self) -> Result<()> {
if let Some(driver) = self.driver.take() {
driver.remove(self)?;
}
Ok(())
}
/// Get device name
pub fn name(&self) -> &str {
&self.name
}
/// Check if device has driver
pub fn has_driver(&self) -> bool {
self.driver.is_some()
}
/// Set private data
pub fn set_private_data<T: Any + Send + Sync>(&mut self, data: T) {
self.private_data = Some(Box::new(data));
}
/// Get private data
pub fn get_private_data<T: Any + Send + Sync>(&self) -> Option<&T> {
self.private_data.as_ref()?.downcast_ref::<T>()
}
/// Power management
pub fn suspend(&mut self) -> Result<()> {
if let Some(driver) = &self.driver {
// We need to clone the driver to avoid borrowing issues
// In a real implementation, we'd use Rc/Arc or other shared ownership
// For now, we'll implement this differently
self.power_state = PowerState::Suspend;
// TODO: Call driver suspend when we have proper
// ownership model
}
Ok(())
}
pub fn resume(&mut self) -> Result<()> {
if let Some(driver) = &self.driver {
// We need to clone the driver to avoid borrowing issues
// In a real implementation, we'd use Rc/Arc or other shared ownership
// For now, we'll implement this differently
self.power_state = PowerState::On;
// TODO: Call driver resume when we have proper
// ownership model
}
Ok(())
}
}
/// Character device structure - Linux compatible
#[derive(Debug)]
pub struct CharDevice {
pub major: u32,
pub minor_start: u32,
pub minor_count: u32,
pub name: String,
pub fops: Option<Box<dyn FileOperations>>,
}
impl CharDevice {
pub fn new(major: u32, minor_start: u32, minor_count: u32, name: String) -> Self {
Self {
major,
minor_start,
minor_count,
name,
fops: None,
}
}
}
/// Block device structure - Linux compatible
#[derive(Debug)]
pub struct BlockDevice {
pub major: u32,
pub minor: u32,
pub name: String,
pub size: u64, // Size in bytes
pub block_size: u32,
}
impl BlockDevice {
pub fn new(major: u32, minor: u32, name: String, size: u64, block_size: u32) -> Self {
Self {
major,
minor,
name,
size,
block_size,
}
}
}
/// File operations structure - Linux compatible
pub trait FileOperations: Send + Sync + core::fmt::Debug {
fn open(&self, inode: &VfsInode, file: &mut VfsFile) -> Result<()>;
fn release(&self, inode: &VfsInode, file: &mut VfsFile) -> Result<()>;
fn read(&self, file: &mut VfsFile, buf: &mut [u8], offset: u64) -> Result<usize>;
fn write(&self, file: &mut VfsFile, buf: &[u8], offset: u64) -> Result<usize>;
fn ioctl(&self, file: &mut VfsFile, cmd: u32, arg: usize) -> Result<usize>;
fn mmap(&self, file: &mut VfsFile, vma: &mut VmaArea) -> Result<()>;
}
/// Re-exports for compatibility with driver.rs
pub use crate::fs::{File, Inode};
/// Global device subsystem
static DEVICE_SUBSYSTEM: Spinlock<DeviceSubsystem> = Spinlock::new(DeviceSubsystem::new());
/// Device subsystem state
struct DeviceSubsystem {
devices: BTreeMap<String, Device>,
char_devices: BTreeMap<u32, CharDevice>, // major -> CharDevice
block_devices: BTreeMap<u32, BlockDevice>, // major -> BlockDevice
next_major: u32,
}
impl DeviceSubsystem {
const fn new() -> Self {
Self {
devices: BTreeMap::new(),
char_devices: BTreeMap::new(),
block_devices: BTreeMap::new(),
next_major: 240, // Start with dynamic major numbers
}
}
fn register_device(&mut self, device: Device) -> Result<()> {
let name = device.name.clone();
if self.devices.contains_key(&name) {
return Err(Error::Busy);
}
self.devices.insert(name, device);
Ok(())
}
fn unregister_device(&mut self, name: &str) -> Result<Device> {
self.devices.remove(name).ok_or(Error::NotFound)
}
#[allow(dead_code)]
fn find_device(&self, name: &str) -> Option<&Device> {
self.devices.get(name)
}
#[allow(dead_code)]
fn find_device_mut(&mut self, name: &str) -> Option<&mut Device> {
self.devices.get_mut(name)
}
fn allocate_major(&mut self) -> u32 {
let major = self.next_major;
self.next_major += 1;
major
}
}
/// Initialize device subsystem
pub fn init() -> Result<()> {
let mut subsystem = DEVICE_SUBSYSTEM.lock();
// Register standard character devices
register_std_char_devices(&mut subsystem)?;
// Register standard block devices
register_std_block_devices(&mut subsystem)?;
crate::info!("Device subsystem initialized");
Ok(())
}
/// Register standard character devices
fn register_std_char_devices(subsystem: &mut DeviceSubsystem) -> Result<()> {
// /dev/null (major 1, minor 3)
let null_dev = CharDevice::new(1, 3, 1, String::from("null"));
subsystem.char_devices.insert(1, null_dev);
// /dev/zero (major 1, minor 5)
let zero_dev = CharDevice::new(1, 5, 1, String::from("zero"));
// Note: This would overwrite the previous entry, so we need a better structure
// For now, simplified
// /dev/random (major 1, minor 8)
let random_dev = CharDevice::new(1, 8, 1, String::from("random"));
// /dev/urandom (major 1, minor 9)
let urandom_dev = CharDevice::new(1, 9, 1, String::from("urandom"));
Ok(())
}
/// Register standard block devices
fn register_std_block_devices(subsystem: &mut DeviceSubsystem) -> Result<()> {
// RAM disk (major 1)
let ramdisk = BlockDevice::new(1, 0, String::from("ram0"), 16 * 1024 * 1024, 4096);
subsystem.block_devices.insert(1, ramdisk);
Ok(())
}
/// Register a device
pub fn register_device(device: Device) -> Result<()> {
let mut subsystem = DEVICE_SUBSYSTEM.lock();
subsystem.register_device(device)
}
/// Unregister a device
pub fn unregister_device(name: &str) -> Result<Device> {
let mut subsystem = DEVICE_SUBSYSTEM.lock();
subsystem.unregister_device(name)
}
/// Find a device by name
pub fn find_device(name: &str) -> Option<&'static Device> {
// TODO: This is unsafe and needs proper lifetime management
// For now, we'll return None to avoid the Clone issue
None
}
/// Register a character device
pub fn register_chrdev(major: u32, name: String, fops: Box<dyn FileOperations>) -> Result<u32> {
let mut subsystem = DEVICE_SUBSYSTEM.lock();
let actual_major = if major == 0 {
subsystem.allocate_major()
} else {
major
};
let mut char_dev = CharDevice::new(actual_major, 0, 256, name);
char_dev.fops = Some(fops);
if subsystem.char_devices.contains_key(&actual_major) {
return Err(Error::Busy);
}
subsystem.char_devices.insert(actual_major, char_dev);
Ok(actual_major)
}
/// Unregister a character device
pub fn unregister_chrdev(major: u32) -> Result<()> {
let mut subsystem = DEVICE_SUBSYSTEM.lock();
if subsystem.char_devices.remove(&major).is_some() {
Ok(())
} else {
Err(Error::NotFound)
}
}
/// List all devices
pub fn list_devices() -> Vec<String> {
let subsystem = DEVICE_SUBSYSTEM.lock();
subsystem.devices.keys().cloned().collect()
}
/// Device tree node - for device tree support
#[derive(Debug)]
pub struct DeviceTreeNode {
pub name: String,
pub compatible: Vec<String>,
pub reg: Vec<u64>,
pub interrupts: Vec<u32>,
pub properties: BTreeMap<String, Vec<u8>>,
}
impl DeviceTreeNode {
pub fn new(name: String) -> Self {
Self {
name,
compatible: Vec::new(),
reg: Vec::new(),
interrupts: Vec::new(),
properties: BTreeMap::new(),
}
}
}

415
kernel/src/device_advanced.rs Archivo normal
Ver fichero

@@ -0,0 +1,415 @@
// SPDX-License-Identifier: GPL-2.0
//! Advanced device driver framework
use alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec};
use core::fmt;
use crate::error::{Error, Result};
use crate::sync::Spinlock;
use crate::types::DeviceId;
/// Device class identifiers
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum DeviceClass {
Block,
Character,
Network,
Storage,
Input,
Display,
Audio,
USB,
PCI,
Platform,
Virtual,
}
/// Device capabilities
#[derive(Debug, Clone)]
pub struct DeviceCapabilities {
pub can_read: bool,
pub can_write: bool,
pub can_seek: bool,
pub can_mmap: bool,
pub can_poll: bool,
pub is_removable: bool,
pub is_hotplug: bool,
pub supports_dma: bool,
}
impl Default for DeviceCapabilities {
fn default() -> Self {
Self {
can_read: true,
can_write: true,
can_seek: false,
can_mmap: false,
can_poll: false,
is_removable: false,
is_hotplug: false,
supports_dma: false,
}
}
}
/// Device power states
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PowerState {
On,
Standby,
Suspend,
Off,
}
/// PCI device information
#[derive(Debug, Clone)]
pub struct PciDeviceInfo {
pub vendor_id: u16,
pub device_id: u16,
pub class_code: u8,
pub subclass: u8,
pub prog_if: u8,
pub revision: u8,
pub bus: u8,
pub device: u8,
pub function: u8,
pub base_addresses: [u32; 6],
pub irq: u8,
}
/// USB device information
#[derive(Debug, Clone)]
pub struct UsbDeviceInfo {
pub vendor_id: u16,
pub product_id: u16,
pub device_class: u8,
pub device_subclass: u8,
pub device_protocol: u8,
pub speed: UsbSpeed,
pub address: u8,
pub configuration: u8,
}
#[derive(Debug, Clone, Copy)]
pub enum UsbSpeed {
Low, // 1.5 Mbps
Full, // 12 Mbps
High, // 480 Mbps
Super, // 5 Gbps
SuperPlus, // 10 Gbps
}
/// Device tree information (for embedded systems)
#[derive(Debug, Clone)]
pub struct DeviceTreeInfo {
pub compatible: Vec<String>,
pub reg: Vec<u64>,
pub interrupts: Vec<u32>,
pub clocks: Vec<u32>,
pub properties: BTreeMap<String, String>,
}
/// Advanced device structure
pub struct AdvancedDevice {
pub id: DeviceId,
pub name: String,
pub class: DeviceClass,
pub capabilities: DeviceCapabilities,
pub power_state: PowerState,
pub parent: Option<DeviceId>,
pub children: Vec<DeviceId>,
// Hardware-specific information
pub pci_info: Option<PciDeviceInfo>,
pub usb_info: Option<UsbDeviceInfo>,
pub dt_info: Option<DeviceTreeInfo>,
// Driver binding
pub driver: Option<Box<dyn AdvancedDeviceDriver>>,
pub driver_data: Option<Box<dyn core::any::Any + Send + Sync>>,
// Resource management
pub io_ports: Vec<(u16, u16)>, // (start, size)
pub memory_regions: Vec<(u64, u64)>, // (base, size)
pub irq_lines: Vec<u32>,
pub dma_channels: Vec<u32>,
// Statistics
pub bytes_read: u64,
pub bytes_written: u64,
pub error_count: u64,
pub last_access: u64,
}
impl fmt::Debug for AdvancedDevice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AdvancedDevice")
.field("id", &self.id)
.field("name", &self.name)
.field("class", &self.class)
.field("capabilities", &self.capabilities)
.field("power_state", &self.power_state)
.field("parent", &self.parent)
.field("children", &self.children)
.finish()
}
}
impl AdvancedDevice {
pub fn new(id: DeviceId, name: String, class: DeviceClass) -> Self {
Self {
id,
name,
class,
capabilities: DeviceCapabilities::default(),
power_state: PowerState::Off,
parent: None,
children: Vec::new(),
pci_info: None,
usb_info: None,
dt_info: None,
driver: None,
driver_data: None,
io_ports: Vec::new(),
memory_regions: Vec::new(),
irq_lines: Vec::new(),
dma_channels: Vec::new(),
bytes_read: 0,
bytes_written: 0,
error_count: 0,
last_access: 0,
}
}
pub fn set_pci_info(&mut self, info: PciDeviceInfo) {
self.pci_info = Some(info);
}
pub fn set_usb_info(&mut self, info: UsbDeviceInfo) {
self.usb_info = Some(info);
}
pub fn add_io_port(&mut self, start: u16, size: u16) {
self.io_ports.push((start, size));
}
pub fn add_memory_region(&mut self, base: u64, size: u64) {
self.memory_regions.push((base, size));
}
pub fn add_irq(&mut self, irq: u32) {
self.irq_lines.push(irq);
}
pub fn set_power_state(&mut self, state: PowerState) -> Result<()> {
// Handle power state transitions
let result = match state {
PowerState::On => {
// Extract driver temporarily to avoid borrow conflicts
if let Some(mut driver) = self.driver.take() {
let result = driver.resume(self);
self.driver = Some(driver);
result
} else {
Ok(())
}
}
PowerState::Off => {
// Extract driver temporarily to avoid borrow conflicts
if let Some(mut driver) = self.driver.take() {
let result = driver.suspend(self);
self.driver = Some(driver);
result
} else {
Ok(())
}
}
_ => Ok(()),
};
if result.is_ok() {
self.power_state = state;
}
result
}
pub fn bind_driver(&mut self, driver: Box<dyn AdvancedDeviceDriver>) -> Result<()> {
if let Err(e) = driver.probe(self) {
return Err(e);
}
self.driver = Some(driver);
Ok(())
}
pub fn unbind_driver(&mut self) -> Result<()> {
if let Some(driver) = self.driver.take() {
driver.remove(self)?;
}
Ok(())
}
}
/// Advanced device driver trait
pub trait AdvancedDeviceDriver: Send + Sync {
fn probe(&self, device: &mut AdvancedDevice) -> Result<()>;
fn remove(&self, device: &mut AdvancedDevice) -> Result<()>;
fn suspend(&self, device: &mut AdvancedDevice) -> Result<()>;
fn resume(&self, device: &mut AdvancedDevice) -> Result<()>;
// Optional methods
fn read(
&self,
_device: &mut AdvancedDevice,
_buf: &mut [u8],
_offset: u64,
) -> Result<usize> {
Err(Error::NotSupported)
}
fn write(&self, _device: &mut AdvancedDevice, _buf: &[u8], _offset: u64) -> Result<usize> {
Err(Error::NotSupported)
}
fn ioctl(&self, _device: &mut AdvancedDevice, _cmd: u32, _arg: usize) -> Result<usize> {
Err(Error::NotSupported)
}
fn interrupt_handler(&self, _device: &mut AdvancedDevice, _irq: u32) -> Result<()> {
Ok(())
}
}
/// Device registry for advanced devices
pub struct AdvancedDeviceRegistry {
devices: BTreeMap<DeviceId, AdvancedDevice>,
next_id: u32,
drivers: Vec<Box<dyn AdvancedDeviceDriver>>,
device_classes: BTreeMap<DeviceClass, Vec<DeviceId>>,
}
impl AdvancedDeviceRegistry {
const fn new() -> Self {
Self {
devices: BTreeMap::new(),
next_id: 1,
drivers: Vec::new(),
device_classes: BTreeMap::new(),
}
}
pub fn register_device(&mut self, mut device: AdvancedDevice) -> Result<DeviceId> {
let id = DeviceId(self.next_id);
self.next_id += 1;
device.id = id;
// Try to bind a compatible driver
for driver in &self.drivers {
if device.driver.is_none() {
if let Ok(_) = driver.probe(&mut device) {
crate::info!("Driver bound to device {}", device.name);
break;
}
}
}
// Add to class index
self.device_classes
.entry(device.class)
.or_insert_with(Vec::new)
.push(id);
self.devices.insert(id, device);
Ok(id)
}
pub fn unregister_device(&mut self, id: DeviceId) -> Result<()> {
if let Some(mut device) = self.devices.remove(&id) {
device.unbind_driver()?;
// Remove from class index
if let Some(devices) = self.device_classes.get_mut(&device.class) {
devices.retain(|&x| x != id);
}
}
Ok(())
}
pub fn register_driver(&mut self, driver: Box<dyn AdvancedDeviceDriver>) {
// Try to bind to existing devices
for device in self.devices.values_mut() {
if device.driver.is_none() {
if let Ok(_) = driver.probe(device) {
crate::info!(
"Driver bound to existing device {}",
device.name
);
}
}
}
self.drivers.push(driver);
}
pub fn get_device(&self, id: DeviceId) -> Option<&AdvancedDevice> {
self.devices.get(&id)
}
pub fn get_device_mut(&mut self, id: DeviceId) -> Option<&mut AdvancedDevice> {
self.devices.get_mut(&id)
}
pub fn find_devices_by_class(&self, class: DeviceClass) -> Vec<DeviceId> {
self.device_classes.get(&class).cloned().unwrap_or_default()
}
pub fn find_devices_by_name(&self, name: &str) -> Vec<DeviceId> {
self.devices
.iter()
.filter(|(_, device)| device.name == name)
.map(|(&id, _)| id)
.collect()
}
pub fn get_device_statistics(&self) -> BTreeMap<DeviceClass, usize> {
let mut stats = BTreeMap::new();
for device in self.devices.values() {
*stats.entry(device.class).or_insert(0) += 1;
}
stats
}
}
/// Global advanced device registry
pub static ADVANCED_DEVICE_REGISTRY: Spinlock<AdvancedDeviceRegistry> =
Spinlock::new(AdvancedDeviceRegistry::new());
/// Initialize advanced device management
pub fn init_advanced() -> Result<()> {
crate::info!("Advanced device management initialized");
Ok(())
}
/// Register a new advanced device
pub fn register_advanced_device(device: AdvancedDevice) -> Result<DeviceId> {
let mut registry = ADVANCED_DEVICE_REGISTRY.lock();
registry.register_device(device)
}
/// Register a device driver
pub fn register_device_driver(driver: Box<dyn AdvancedDeviceDriver>) {
let mut registry = ADVANCED_DEVICE_REGISTRY.lock();
registry.register_driver(driver);
}
/// Find devices by class
pub fn find_devices_by_class(class: DeviceClass) -> Vec<DeviceId> {
let registry = ADVANCED_DEVICE_REGISTRY.lock();
registry.find_devices_by_class(class)
}
/// Get device statistics
pub fn get_device_statistics() -> BTreeMap<DeviceClass, usize> {
let registry = ADVANCED_DEVICE_REGISTRY.lock();
registry.get_device_statistics()
}

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

@@ -0,0 +1,301 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel diagnostics and health monitoring
use alloc::{format, string::String, vec::Vec};
use core::fmt::Write;
use crate::error::Result;
use crate::sync::Spinlock;
use crate::time::get_jiffies;
use crate::types::Jiffies;
/// 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);
}
}

404
kernel/src/driver.rs Archivo normal
Ver fichero

@@ -0,0 +1,404 @@
// SPDX-License-Identifier: GPL-2.0
//! Driver framework compatible with Linux kernel
use alloc::{
boxed::Box,
collections::BTreeMap,
string::{String, ToString},
vec::Vec,
};
use crate::device::Device;
use crate::error::{Error, Result};
use crate::sync::Spinlock; // Add ToString
/// Driver trait - Linux compatible
pub trait Driver: Send + Sync + core::fmt::Debug {
/// Driver name
fn name(&self) -> &str;
/// Probe function - called when device is found
fn probe(&self, device: &mut Device) -> Result<()>;
/// Remove function - called when device is removed
fn remove(&self, device: &mut Device) -> Result<()>;
/// Suspend function - power management
fn suspend(&self, device: &mut Device) -> Result<()> {
// Default implementation does nothing
Ok(())
}
/// Resume function - power management
fn resume(&self, device: &mut Device) -> Result<()> {
// Default implementation does nothing
Ok(())
}
/// Shutdown function - system shutdown
fn shutdown(&self, device: &mut Device) {
// Default implementation does nothing
}
}
/// Driver operations for character devices
pub trait CharDriverOps: Send + Sync {
fn open(&self, inode: &crate::device::Inode, file: &mut crate::device::File) -> Result<()>;
fn release(
&self,
inode: &crate::device::Inode,
file: &mut crate::device::File,
) -> Result<()>;
fn read(
&self,
file: &mut crate::device::File,
buf: &mut [u8],
offset: u64,
) -> Result<usize>;
fn write(&self, file: &mut crate::device::File, buf: &[u8], offset: u64) -> Result<usize>;
fn ioctl(&self, file: &mut crate::device::File, cmd: u32, arg: usize) -> Result<usize>;
}
/// Driver operations for block devices
pub trait BlockDriverOps: Send + Sync {
fn read_block(&self, block: u64, buffer: &mut [u8]) -> Result<usize>;
fn write_block(&self, block: u64, buffer: &[u8]) -> Result<usize>;
fn get_block_size(&self) -> u32;
fn get_total_blocks(&self) -> u64;
fn flush(&self) -> Result<()>;
}
/// Platform driver - for platform devices
pub trait PlatformDriver: Driver {
/// Match function - check if driver supports device
fn match_device(&self, device: &Device) -> bool;
/// Get supported device IDs
fn device_ids(&self) -> &[DeviceId];
}
/// Device ID structure - for driver matching
#[derive(Debug, Clone)]
pub struct DeviceId {
pub name: String,
pub vendor_id: Option<u32>,
pub device_id: Option<u32>,
pub class: Option<u32>,
pub compatible: Vec<String>, // Device tree compatible strings
}
impl DeviceId {
pub fn new(name: String) -> Self {
Self {
name,
vendor_id: None,
device_id: None,
class: None,
compatible: Vec::new(),
}
}
pub fn with_vendor_device(mut self, vendor_id: u32, device_id: u32) -> Self {
self.vendor_id = Some(vendor_id);
self.device_id = Some(device_id);
self
}
pub fn with_compatible(mut self, compatible: Vec<String>) -> Self {
self.compatible = compatible;
self
}
}
/// PCI driver - for PCI devices
pub trait PciDriver: Driver {
/// PCI device IDs supported by this driver
fn pci_ids(&self) -> &[PciDeviceId];
/// PCI-specific probe
fn pci_probe(&self, pci_dev: &mut PciDevice) -> Result<()>;
/// PCI-specific remove
fn pci_remove(&self, pci_dev: &mut PciDevice) -> Result<()>;
}
/// PCI device ID
#[derive(Debug, Clone, Copy)]
pub struct PciDeviceId {
pub vendor: u16,
pub device: u16,
pub subvendor: u16,
pub subdevice: u16,
pub class: u32,
pub class_mask: u32,
}
impl PciDeviceId {
pub const fn new(vendor: u16, device: u16) -> Self {
Self {
vendor,
device,
subvendor: 0xFFFF, // PCI_ANY_ID
subdevice: 0xFFFF,
class: 0,
class_mask: 0,
}
}
}
/// PCI device structure
#[derive(Debug, Clone)]
pub struct PciDevice {
pub vendor: u16,
pub device: u16,
pub subsystem_vendor: u16,
pub subsystem_device: u16,
pub class: u32,
pub revision: u8,
pub bus: u8,
pub slot: u8,
pub function: u8,
pub irq: u32,
pub bars: [PciBar; 6],
}
/// PCI Base Address Register
#[derive(Debug, Clone, Copy)]
pub struct PciBar {
pub address: u64,
pub size: u64,
pub flags: u32,
}
impl PciBar {
pub fn new() -> Self {
Self {
address: 0,
size: 0,
flags: 0,
}
}
pub fn is_io(&self) -> bool {
self.flags & 1 != 0
}
pub fn is_memory(&self) -> bool {
!self.is_io()
}
pub fn is_64bit(&self) -> bool {
self.is_memory() && (self.flags & 0x6) == 0x4
}
}
/// USB driver - for USB devices
pub trait UsbDriver: Driver {
/// USB device IDs supported by this driver
fn usb_ids(&self) -> &[UsbDeviceId];
/// USB-specific probe
fn usb_probe(&self, usb_dev: &mut UsbDevice) -> Result<()>;
/// USB-specific disconnect
fn usb_disconnect(&self, usb_dev: &mut UsbDevice) -> Result<()>;
}
/// USB device ID
#[derive(Debug, Clone, Copy)]
pub struct UsbDeviceId {
pub vendor: u16,
pub product: u16,
pub device_class: u8,
pub device_subclass: u8,
pub device_protocol: u8,
pub interface_class: u8,
pub interface_subclass: u8,
pub interface_protocol: u8,
}
/// USB device structure
#[derive(Debug)]
pub struct UsbDevice {
pub vendor: u16,
pub product: u16,
pub device_class: u8,
pub device_subclass: u8,
pub device_protocol: u8,
pub speed: UsbSpeed,
pub address: u8,
pub configuration: u8,
}
/// USB speeds
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UsbSpeed {
Low, // 1.5 Mbps
Full, // 12 Mbps
High, // 480 Mbps
Super, // 5 Gbps
SuperPlus, // 10 Gbps
}
/// Global driver subsystem
static DRIVER_SUBSYSTEM: Spinlock<DriverSubsystem> = Spinlock::new(DriverSubsystem::new());
/// Driver subsystem state
struct DriverSubsystem {
drivers: BTreeMap<String, Box<dyn Driver>>,
platform_drivers: Vec<Box<dyn PlatformDriver>>,
pci_drivers: Vec<Box<dyn PciDriver>>,
usb_drivers: Vec<Box<dyn UsbDriver>>,
}
impl DriverSubsystem {
const fn new() -> Self {
Self {
drivers: BTreeMap::new(),
platform_drivers: Vec::new(),
pci_drivers: Vec::new(),
usb_drivers: Vec::new(),
}
}
fn register_driver(&mut self, driver: Box<dyn Driver>) -> Result<()> {
let name = driver.name().to_string();
if self.drivers.contains_key(&name) {
return Err(Error::Busy);
}
self.drivers.insert(name, driver);
Ok(())
}
fn unregister_driver(&mut self, name: &str) -> Result<()> {
if self.drivers.remove(name).is_some() {
Ok(())
} else {
Err(Error::NotFound)
}
}
#[allow(dead_code)]
fn find_driver(&self, name: &str) -> Option<&dyn Driver> {
self.drivers.get(name).map(|d| d.as_ref())
}
}
/// Register a driver
pub fn register_driver(driver: Box<dyn Driver>) -> Result<()> {
let mut subsystem = DRIVER_SUBSYSTEM.lock();
let name = driver.name().to_string();
subsystem.register_driver(driver)?;
crate::info!("Registered driver: {}", name);
Ok(())
}
/// Unregister a driver
pub fn unregister_driver(name: &str) -> Result<()> {
let mut subsystem = DRIVER_SUBSYSTEM.lock();
subsystem.unregister_driver(name)?;
crate::info!("Unregistered driver: {}", name);
Ok(())
}
/// Register a platform driver
pub fn register_platform_driver(driver: Box<dyn PlatformDriver>) -> Result<()> {
let mut subsystem = DRIVER_SUBSYSTEM.lock();
let name = driver.name().to_string();
// Also register as a regular driver
let driver_copy = unsafe {
// This is a bit of a hack - we need to clone the driver
// In a real implementation, we'd use Arc or similar
core::mem::transmute::<*const dyn PlatformDriver, Box<dyn Driver>>(
driver.as_ref() as *const dyn PlatformDriver
)
};
subsystem.register_driver(driver_copy)?;
subsystem.platform_drivers.push(driver);
crate::info!("Registered platform driver: {}", name);
Ok(())
}
/// Register a PCI driver
pub fn register_pci_driver(driver: Box<dyn PciDriver>) -> Result<()> {
let mut subsystem = DRIVER_SUBSYSTEM.lock();
let name = driver.name().to_string();
subsystem.pci_drivers.push(driver);
crate::info!("Registered PCI driver: {}", name);
Ok(())
}
/// Register a USB driver
pub fn register_usb_driver(driver: Box<dyn UsbDriver>) -> Result<()> {
let mut subsystem = DRIVER_SUBSYSTEM.lock();
let name = driver.name().to_string();
subsystem.usb_drivers.push(driver);
crate::info!("Registered USB driver: {}", name);
Ok(())
}
/// Find and match a driver for a device
pub fn match_driver(device: &Device) -> Option<String> {
let subsystem = DRIVER_SUBSYSTEM.lock();
// Try platform drivers first
for driver in &subsystem.platform_drivers {
if driver.match_device(device) {
return Some(driver.name().to_string());
}
}
// TODO: Try PCI, USB, etc. drivers based on device type
None
}
/// Get list of registered drivers
pub fn list_drivers() -> Vec<String> {
let subsystem = DRIVER_SUBSYSTEM.lock();
subsystem.drivers.keys().cloned().collect()
}
/// Module macros for easier driver registration
#[macro_export]
macro_rules! platform_driver {
($driver:ident) => {
#[no_mangle]
pub extern "C" fn init_module() -> core::ffi::c_int {
match $crate::driver::register_platform_driver(Box::new($driver)) {
Ok(()) => 0,
Err(e) => e.to_errno(),
}
}
#[no_mangle]
pub extern "C" fn cleanup_module() {
$crate::driver::unregister_driver(stringify!($driver)).ok();
}
};
}
pub fn pci_config_read(bus: u8, device: u8, function: u8, offset: u8) -> u32 {
crate::hardware::pci_config_read(bus, device, function, offset)
}
#[macro_export]
macro_rules! pci_driver {
($driver:ident) => {
#[no_mangle]
pub extern "C" fn init_module() -> core::ffi::c_int {
match $crate::driver::register_pci_driver(Box::new($driver)) {
Ok(()) => 0,
Err(e) => e.to_errno(),
}
}
#[no_mangle]
pub extern "C" fn cleanup_module() {
$crate::driver::unregister_driver(stringify!($driver)).ok();
}
};
}

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

@@ -0,0 +1,137 @@
// SPDX-License-Identifier: GPL-2.0
//! Driver initialization and management
use crate::error::Result;
use crate::{info, warn};
/// Initialize all built-in drivers
pub fn init_drivers() -> Result<()> {
info!("Initializing built-in drivers");
// Initialize keyboard driver
init_keyboard_driver()?;
// Initialize serial driver
init_serial_driver()?;
// Initialize ramdisk driver
init_ramdisk_driver()?;
info!("Built-in drivers initialized");
Ok(())
}
/// Initialize PS/2 keyboard driver
fn init_keyboard_driver() -> Result<()> {
info!("Initializing PS/2 keyboard driver");
// Register keyboard interrupt handler (IRQ 1)
if let Err(e) = crate::interrupt::request_irq(
1,
keyboard_interrupt_handler,
0,
"keyboard",
core::ptr::null_mut(),
) {
warn!("Failed to register keyboard interrupt: {}", e);
return Err(e);
}
info!("PS/2 keyboard driver initialized");
Ok(())
}
/// Initialize serial driver
fn init_serial_driver() -> Result<()> {
info!("Initializing serial driver");
// Register serial interrupt handlers (IRQ 3 and 4)
if let Err(e) = crate::interrupt::request_irq(
3,
serial_interrupt_handler,
0,
"serial",
core::ptr::null_mut(),
) {
warn!("Failed to register serial interrupt: {}", e);
}
if let Err(e) = crate::interrupt::request_irq(
4,
serial_interrupt_handler,
0,
"serial",
core::ptr::null_mut(),
) {
warn!("Failed to register serial interrupt: {}", e);
}
info!("Serial driver initialized");
Ok(())
}
/// Initialize ramdisk driver
fn init_ramdisk_driver() -> Result<()> {
info!("Initializing ramdisk driver");
// TODO: Create ramdisk device
// This would typically involve:
// 1. Allocating memory for the ramdisk
// 2. Registering the device with the block device subsystem
// 3. Setting up device file operations
info!("Ramdisk driver initialized");
Ok(())
}
/// Keyboard interrupt handler
fn keyboard_interrupt_handler(irq: u32, dev_id: *mut u8) -> crate::interrupt::IrqReturn {
// Read the scan code from the keyboard controller
let scancode = unsafe { crate::arch::x86_64::port::inb(0x60) };
// Convert scan code to ASCII (simplified)
if scancode < 128 {
let ascii = SCANCODE_TO_ASCII[scancode as usize];
if ascii != 0 {
// Send character to kernel shell
if let Err(e) = crate::shell::shell_input(ascii as char) {
crate::warn!("Failed to process shell input: {}", e);
}
}
}
crate::interrupt::IrqReturn::Handled
}
/// Serial interrupt handler
fn serial_interrupt_handler(irq: u32, dev_id: *mut u8) -> crate::interrupt::IrqReturn {
// TODO: Handle serial port interrupts
// This would typically involve reading from the serial port
// and handling incoming data
crate::interrupt::IrqReturn::Handled
}
/// Keyboard scan code to ASCII mapping (simplified US layout)
const SCANCODE_TO_ASCII: [u8; 128] = [
0, 27, b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'0', b'-', b'=',
8, // 0-14
b'\t', b'q', b'w', b'e', b'r', b't', b'y', b'u', b'i', b'o', b'p', b'[', b']',
b'\n', // 15-28
0, // 29 ctrl
b'a', b's', b'd', b'f', b'g', b'h', b'j', b'k', b'l', b';', b'\'', b'`', // 30-41
0, // 42 left shift
b'\\', b'z', b'x', b'c', b'v', b'b', b'n', b'm', b',', b'.', b'/', // 43-53
0, // 54 right shift
b'*', 0, // 55-56 alt
b' ', // 57 space
0, // 58 caps lock
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 59-68 F1-F10
0, 0, // 69-70 num lock, scroll lock
b'7', b'8', b'9', b'-', b'4', b'5', b'6', b'+', b'1', b'2', b'3', b'0',
b'.', // 71-83 numpad
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 84-99
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100-115
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 116-127
];

Ver fichero

@@ -0,0 +1,567 @@
// SPDX-License-Identifier: GPL-2.0
//! Enhanced preemptive scheduler with improved context switching
use alloc::{
collections::{BTreeMap, VecDeque},
string::{String, ToString},
vec::Vec,
};
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use crate::error::{Error, Result};
use crate::sync::Spinlock;
use crate::time::get_jiffies;
use crate::types::{Jiffies, Tid};
/// Preemption counter
static PREEMPTION_COUNT: AtomicU64 = AtomicU64::new(0);
/// Get preemption count
pub fn get_preemption_count() -> u64 {
PREEMPTION_COUNT.load(Ordering::Relaxed)
}
/// Increment preemption counter
pub fn increment_preemption_count() {
PREEMPTION_COUNT.fetch_add(1, Ordering::Relaxed);
}
/// Enhanced task state
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TaskState {
Running,
Ready,
Blocked,
Sleeping,
Zombie,
Dead,
}
/// Task priority levels
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Priority {
Critical = 0,
High = 1,
Normal = 2,
Low = 3,
Background = 4,
}
/// Enhanced task structure for better scheduling
#[derive(Debug, Clone)]
pub struct Task {
pub tid: Tid,
pub name: String,
pub state: TaskState,
pub priority: Priority,
pub vruntime: u64, // Virtual runtime for fair scheduling
pub exec_time: u64, // Total execution time
pub sleep_until: Option<Jiffies>, // Wake up time if sleeping
pub last_scheduled: Jiffies, // Last time this task was scheduled
pub cpu_affinity: u32, // CPU affinity mask
pub nice: i8, // Nice value (-20 to 19)
pub preempt_count: u32, // Preemption counter
}
impl Task {
pub fn new(tid: Tid, name: String, priority: Priority) -> Self {
let now = get_jiffies();
Self {
tid,
name,
state: TaskState::Ready,
priority,
vruntime: 0,
exec_time: 0,
sleep_until: None,
last_scheduled: now,
cpu_affinity: 0xFFFFFFFF, // All CPUs by default
nice: 0,
preempt_count: 0,
}
}
/// Check if task is runnable
pub fn is_runnable(&self) -> bool {
match self.state {
TaskState::Ready | TaskState::Running => true,
TaskState::Sleeping => {
if let Some(wake_time) = self.sleep_until {
get_jiffies() >= wake_time
} else {
false
}
}
_ => false,
}
}
/// Update virtual runtime for fair scheduling
pub fn update_vruntime(&mut self, delta: u64) {
// Apply nice value weighting
let weight = nice_to_weight(self.nice);
self.vruntime += (delta * 1024) / weight;
self.exec_time += delta;
}
/// Wake up sleeping task
pub fn wake_up(&mut self) {
if self.state == TaskState::Sleeping {
self.state = TaskState::Ready;
self.sleep_until = None;
}
}
}
/// Convert nice value to weight for scheduling calculations
fn nice_to_weight(nice: i8) -> u64 {
// Weight table based on nice values (exponential scale)
match nice {
-20..=-15 => 88761,
-14..=-10 => 71755,
-9..=-5 => 56483,
-4..=0 => 1024,
1..=5 => 820,
6..=10 => 655,
11..=15 => 526,
16..=19 => 423,
_ => 1024, // Default weight
}
}
/// Run queue for a specific priority level
#[derive(Debug)]
struct RunQueue {
tasks: VecDeque<Tid>,
total_weight: u64,
min_vruntime: u64,
}
impl RunQueue {
fn new() -> Self {
Self {
tasks: VecDeque::new(),
total_weight: 0,
min_vruntime: 0,
}
}
fn add_task(&mut self, tid: Tid) {
if !self.tasks.contains(&tid) {
self.tasks.push_back(tid);
}
}
fn remove_task(&mut self, tid: Tid) -> bool {
if let Some(pos) = self.tasks.iter().position(|&t| t == tid) {
self.tasks.remove(pos);
true
} else {
false
}
}
fn next_task(&mut self) -> Option<Tid> {
self.tasks.pop_front()
}
fn is_empty(&self) -> bool {
self.tasks.is_empty()
}
}
/// Enhanced scheduler with preemptive multitasking
pub struct EnhancedScheduler {
tasks: BTreeMap<Tid, Task>,
run_queues: BTreeMap<Priority, RunQueue>,
current_task: Option<Tid>,
idle_task: Option<Tid>,
next_tid: AtomicU64,
total_context_switches: AtomicU64,
preemption_enabled: AtomicBool,
time_slice: u64, // Time slice in jiffies
}
impl EnhancedScheduler {
pub fn new() -> Self {
let mut run_queues = BTreeMap::new();
run_queues.insert(Priority::Critical, RunQueue::new());
run_queues.insert(Priority::High, RunQueue::new());
run_queues.insert(Priority::Normal, RunQueue::new());
run_queues.insert(Priority::Low, RunQueue::new());
run_queues.insert(Priority::Background, RunQueue::new());
Self {
tasks: BTreeMap::new(),
run_queues,
current_task: None,
idle_task: None,
next_tid: AtomicU64::new(1),
total_context_switches: AtomicU64::new(0),
preemption_enabled: AtomicBool::new(true),
time_slice: 10, // 10ms default time slice
}
}
/// Add a new task to the scheduler
pub fn add_task(&mut self, name: String, priority: Priority) -> Result<Tid> {
let tid = Tid(self.next_tid.fetch_add(1, Ordering::SeqCst) as u32);
let task = Task::new(tid, name, priority);
self.tasks.insert(tid, task);
if let Some(queue) = self.run_queues.get_mut(&priority) {
queue.add_task(tid);
}
Ok(tid)
}
/// Remove a task from the scheduler
pub fn remove_task(&mut self, tid: Tid) -> Result<()> {
if let Some(task) = self.tasks.remove(&tid) {
if let Some(queue) = self.run_queues.get_mut(&task.priority) {
queue.remove_task(tid);
}
if self.current_task == Some(tid) {
self.current_task = None;
}
Ok(())
} else {
Err(Error::NotFound)
}
}
/// Get the next task to run
pub fn schedule(&mut self) -> Option<Tid> {
// Check if current task can continue running
if let Some(current_tid) = self.current_task {
if let Some(current_task) = self.tasks.get(&current_tid) {
if current_task.is_runnable() && !self.should_preempt(current_task)
{
return Some(current_tid);
}
}
}
// Find the next task to run (priority-based with fair scheduling within
// priority)
for priority in [
Priority::Critical,
Priority::High,
Priority::Normal,
Priority::Low,
Priority::Background,
] {
if let Some(queue) = self.run_queues.get_mut(&priority) {
if !queue.is_empty() {
// For fair scheduling, pick task with lowest vruntime
let mut best_task = None;
let mut min_vruntime = u64::MAX;
for &tid in &queue.tasks {
if let Some(task) = self.tasks.get(&tid) {
if task.is_runnable()
&& task.vruntime < min_vruntime
{
min_vruntime = task.vruntime;
best_task = Some(tid);
}
}
}
if let Some(tid) = best_task {
// Remove from current position and add to back for
// round-robin
queue.remove_task(tid);
queue.add_task(tid);
return Some(tid);
}
}
}
}
// No runnable tasks, return idle task or None
self.idle_task
}
/// Check if current task should be preempted
fn should_preempt(&self, current_task: &Task) -> bool {
if !self.preemption_enabled.load(Ordering::SeqCst) {
return false;
}
let now = get_jiffies();
let time_running = now - current_task.last_scheduled;
// Preempt if time slice exceeded
if time_running.as_u64() > self.time_slice {
return true;
}
// Preempt if higher priority task is available
for priority in [Priority::Critical, Priority::High] {
if priority < current_task.priority {
if let Some(queue) = self.run_queues.get(&priority) {
if !queue.is_empty() {
return true;
}
}
}
}
false
}
/// Switch to a new task
pub fn switch_to(&mut self, tid: Tid) -> Result<()> {
if let Some(task) = self.tasks.get_mut(&tid) {
task.state = TaskState::Running;
task.last_scheduled = get_jiffies();
self.current_task = Some(tid);
self.total_context_switches.fetch_add(1, Ordering::SeqCst);
Ok(())
} else {
Err(Error::NotFound)
}
}
/// Put current task to sleep for specified duration
pub fn sleep(&mut self, duration_jiffies: u64) -> Result<()> {
if let Some(current_tid) = self.current_task {
if let Some(task) = self.tasks.get_mut(&current_tid) {
task.state = TaskState::Sleeping;
task.sleep_until = Some(get_jiffies() + duration_jiffies);
self.current_task = None;
Ok(())
} else {
Err(Error::NotFound)
}
} else {
Err(Error::InvalidArgument)
}
}
/// Wake up sleeping tasks
pub fn wake_up_sleepers(&mut self) {
let now = get_jiffies();
for task in self.tasks.values_mut() {
if task.state == TaskState::Sleeping {
if let Some(wake_time) = task.sleep_until {
if now >= wake_time {
task.wake_up();
// Add back to run queue
if let Some(queue) =
self.run_queues.get_mut(&task.priority)
{
queue.add_task(task.tid);
}
}
}
}
}
}
/// Update virtual runtime for current task
pub fn update_current_task(&mut self, time_delta: u64) {
if let Some(current_tid) = self.current_task {
if let Some(task) = self.tasks.get_mut(&current_tid) {
task.update_vruntime(time_delta);
}
}
}
/// Get scheduler statistics
pub fn get_stats(&self) -> SchedulerStats {
let total_tasks = self.tasks.len();
let runnable_tasks = self
.tasks
.values()
.filter(|task| task.is_runnable())
.count();
let sleeping_tasks = self
.tasks
.values()
.filter(|task| task.state == TaskState::Sleeping)
.count();
SchedulerStats {
total_tasks,
runnable_tasks,
sleeping_tasks,
context_switches: self.total_context_switches.load(Ordering::SeqCst),
preemption_enabled: self.preemption_enabled.load(Ordering::SeqCst),
current_task: self.current_task,
}
}
/// Enable/disable preemption
pub fn set_preemption(&self, enabled: bool) {
self.preemption_enabled.store(enabled, Ordering::SeqCst);
}
/// Get current task
pub fn current_task(&self) -> Option<Tid> {
self.current_task
}
/// Get task by ID
pub fn get_task(&self, tid: Tid) -> Option<&Task> {
self.tasks.get(&tid)
}
/// Set task priority
pub fn set_priority(&mut self, tid: Tid, priority: Priority) -> Result<()> {
if let Some(task) = self.tasks.get_mut(&tid) {
let old_priority = task.priority;
task.priority = priority;
// Move task between run queues
if let Some(old_queue) = self.run_queues.get_mut(&old_priority) {
old_queue.remove_task(tid);
}
if task.is_runnable() {
if let Some(new_queue) = self.run_queues.get_mut(&priority) {
new_queue.add_task(tid);
}
}
Ok(())
} else {
Err(Error::NotFound)
}
}
/// Create idle task
pub fn create_idle_task(&mut self) -> Result<Tid> {
let tid = self.add_task("idle".to_string(), Priority::Background)?;
self.idle_task = Some(tid);
Ok(tid)
}
}
/// Scheduler statistics
#[derive(Debug, Clone)]
pub struct SchedulerStats {
pub total_tasks: usize,
pub runnable_tasks: usize,
pub sleeping_tasks: usize,
pub context_switches: u64,
pub preemption_enabled: bool,
pub current_task: Option<Tid>,
}
/// Global enhanced scheduler
static ENHANCED_SCHEDULER: Spinlock<Option<EnhancedScheduler>> = Spinlock::new(None);
/// Helper to get scheduler reference safely
fn with_scheduler<T, F>(f: F) -> Option<T>
where
F: FnOnce(&mut EnhancedScheduler) -> T,
{
let mut scheduler_option = ENHANCED_SCHEDULER.lock();
if let Some(ref mut scheduler) = *scheduler_option {
Some(f(scheduler))
} else {
None
}
}
/// Helper to get read-only scheduler reference safely
fn with_scheduler_read<T, F>(f: F) -> Option<T>
where
F: FnOnce(&EnhancedScheduler) -> T,
{
let scheduler_option = ENHANCED_SCHEDULER.lock();
if let Some(ref scheduler) = *scheduler_option {
Some(f(scheduler))
} else {
None
}
}
/// Initialize enhanced scheduler
pub fn init_enhanced_scheduler() -> Result<()> {
let mut scheduler_option = ENHANCED_SCHEDULER.lock();
if scheduler_option.is_none() {
let mut scheduler = EnhancedScheduler::new();
scheduler.create_idle_task()?;
*scheduler_option = Some(scheduler);
}
crate::info!("Enhanced scheduler initialized");
Ok(())
}
/// Schedule next task
pub fn schedule_next() -> Option<Tid> {
with_scheduler(|scheduler| {
scheduler.wake_up_sleepers();
scheduler.schedule()
})
.flatten()
}
/// Add new task to scheduler
pub fn add_task(name: String, priority: Priority) -> Result<Tid> {
with_scheduler(|scheduler| scheduler.add_task(name, priority))
.unwrap_or(Err(Error::NotInitialized))
}
/// Remove task from scheduler
pub fn remove_task(tid: Tid) -> Result<()> {
with_scheduler(|scheduler| scheduler.remove_task(tid)).unwrap_or(Err(Error::NotInitialized))
}
/// Switch to specific task
pub fn switch_to_task(tid: Tid) -> Result<()> {
with_scheduler(|scheduler| scheduler.switch_to(tid)).unwrap_or(Err(Error::NotInitialized))
}
/// Put current task to sleep
pub fn sleep_current_task(duration_jiffies: u64) -> Result<()> {
with_scheduler(|scheduler| scheduler.sleep(duration_jiffies))
.unwrap_or(Err(Error::NotInitialized))
}
/// Get scheduler statistics
pub fn get_scheduler_stats() -> SchedulerStats {
with_scheduler_read(|scheduler| scheduler.get_stats()).unwrap_or(SchedulerStats {
total_tasks: 0,
runnable_tasks: 0,
sleeping_tasks: 0,
context_switches: 0,
preemption_enabled: false,
current_task: None,
})
}
/// Update current task runtime
pub fn update_current_task_runtime(time_delta: u64) {
with_scheduler(|scheduler| {
scheduler.update_current_task(time_delta);
});
}
/// Get current running task
pub fn get_current_task() -> Option<Tid> {
with_scheduler_read(|scheduler| scheduler.current_task()).flatten()
}
/// Set task priority
pub fn set_task_priority(tid: Tid, priority: Priority) -> Result<()> {
with_scheduler(|scheduler| scheduler.set_priority(tid, priority))
.unwrap_or(Err(Error::NotInitialized))
}
/// Enable or disable preemption
pub fn set_preemption_enabled(enabled: bool) {
with_scheduler(|scheduler| {
scheduler.set_preemption(enabled);
});
}

199
kernel/src/error.rs Archivo normal
Ver fichero

@@ -0,0 +1,199 @@
// SPDX-License-Identifier: GPL-2.0
//! Error handling types and utilities
use core::fmt;
/// Kernel error type
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
/// Out of memory
OutOfMemory,
/// Invalid argument
InvalidArgument,
/// Permission denied
PermissionDenied,
/// Resource busy
Busy,
/// Resource busy (alias for IPC)
ResourceBusy,
/// Resource not found
NotFound,
/// Resource already exists
AlreadyExists,
/// Operation not supported
NotSupported,
/// I/O error
Io,
/// Generic I/O error (EIO)
EIO,
/// Interrupted operation
Interrupted,
/// Resource temporarily unavailable
WouldBlock,
/// Device error
Device,
/// Generic error
Generic,
/// Invalid operation
InvalidOperation,
/// Timeout
Timeout,
/// Not initialized
NotInitialized, // New error variant
/// Network unreachable
NetworkUnreachable,
/// Network is down
NetworkDown,
/// Device not found
DeviceNotFound,
/// Out of memory (ENOMEM)
ENOMEM,
/// Host unreachable (EHOSTUNREACH)
EHOSTUNREACH,
// Linux-compatible errno values
/// Operation not permitted (EPERM)
EPERM,
/// No such file or directory (ENOENT)
ENOENT,
/// Bad file descriptor (EBADF)
EBADF,
/// No such device (ENODEV)
ENODEV,
/// Invalid argument (EINVAL)
EINVAL,
/// No space left on device (ENOSPC)
ENOSPC,
/// Inappropriate ioctl for device (ENOTTY)
ENOTTY,
/// Illegal seek (ESPIPE)
ESPIPE,
/// No data available (ENODATA)
ENODATA,
/// Function not implemented (ENOSYS)
ENOSYS,
/// Not a directory (ENOTDIR)
ENOTDIR,
/// Is a directory (EISDIR)
EISDIR,
/// File exists (EEXIST)
EEXIST,
/// Directory not empty (ENOTEMPTY)
ENOTEMPTY,
/// No child process (ECHILD)
ECHILD,
/// No such process (ESRCH)
ESRCH,
}
impl Error {
/// Convert error to errno value
pub fn to_errno(self) -> i32 {
match self {
Error::OutOfMemory => -12, // ENOMEM
Error::InvalidArgument => -22, // EINVAL
Error::PermissionDenied => -1, // EPERM
Error::Busy => -16, // EBUSY
Error::ResourceBusy => -16, // EBUSY (alias)
Error::NotFound => -2, // ENOENT
Error::AlreadyExists => -17, // EEXIST
Error::NotSupported => -38, // ENOSYS
Error::Io => -5, // EIO
Error::Interrupted => -4, // EINTR
Error::WouldBlock => -11, // EAGAIN
Error::Device => -19, // ENODEV
Error::Generic => -1, // EPERM
Error::InvalidOperation => -1, // EPERM
Error::Timeout => -110, // ETIMEDOUT
Error::NotInitialized => -6, // ENXIO
// Linux errno mappings
Error::EPERM => -1, // EPERM
Error::ENOENT => -2, // ENOENT
Error::EBADF => -9, // EBADF
Error::ENODEV => -19, // ENODEV
Error::EINVAL => -22, // EINVAL
Error::ENOSPC => -28, // ENOSPC
Error::ENOTTY => -25, // ENOTTY
Error::ESPIPE => -29, // ESPIPE
Error::ENODATA => -61, // ENODATA
Error::ENOSYS => -38, // ENOSYS
Error::ENOTDIR => -20, // ENOTDIR
Error::EISDIR => -21, // EISDIR
Error::EEXIST => -17, // EEXIST
Error::ENOTEMPTY => -39, // ENOTEMPTY
Error::ECHILD => -10, // ECHILD
Error::ESRCH => -3, // ESRCH
Error::NetworkUnreachable => -101, // ENETUNREACH
Error::NetworkDown => -100, // ENETDOWN
Error::DeviceNotFound => -19, // ENODEV
Error::ENOMEM => -12, // ENOMEM
Error::EHOSTUNREACH => -113, // EHOSTUNREACH
Error::EIO => -5, // EIO
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::OutOfMemory => write!(f, "Out of memory"),
Error::InvalidArgument => write!(f, "Invalid argument"),
Error::PermissionDenied => write!(f, "Permission denied"),
Error::Busy => write!(f, "Resource busy"),
Error::ResourceBusy => write!(f, "Resource busy"),
Error::NotFound => write!(f, "Resource not found"),
Error::AlreadyExists => write!(f, "Resource already exists"),
Error::NotSupported => write!(f, "Operation not supported"),
Error::Io => write!(f, "I/O error"),
Error::Interrupted => write!(f, "Interrupted operation"),
Error::WouldBlock => write!(f, "Resource temporarily unavailable"),
Error::Device => write!(f, "Device error"),
Error::Generic => write!(f, "Generic error"),
Error::InvalidOperation => write!(f, "Invalid operation"),
Error::Timeout => write!(f, "Operation timed out"),
Error::NotInitialized => write!(f, "Not initialized"),
Error::NetworkUnreachable => write!(f, "Network unreachable"),
Error::NetworkDown => write!(f, "Network is down"),
Error::DeviceNotFound => write!(f, "Device not found"),
Error::ENOMEM => write!(f, "Out of memory"),
Error::EHOSTUNREACH => write!(f, "Host unreachable"),
// Linux errno variants
Error::EPERM => write!(f, "Operation not permitted"),
Error::ENOENT => write!(f, "No such file or directory"),
Error::EBADF => write!(f, "Bad file descriptor"),
Error::ENODEV => write!(f, "No such device"),
Error::EINVAL => write!(f, "Invalid argument"),
Error::ENOSPC => write!(f, "No space left on device"),
Error::ENOTTY => write!(f, "Inappropriate ioctl for device"),
Error::ESPIPE => write!(f, "Illegal seek"),
Error::ENODATA => write!(f, "No data available"),
Error::ENOSYS => write!(f, "Function not implemented"),
Error::ENOTDIR => write!(f, "Not a directory"),
Error::EISDIR => write!(f, "Is a directory"),
Error::EEXIST => write!(f, "File exists"),
Error::ENOTEMPTY => write!(f, "Directory not empty"),
Error::ECHILD => write!(f, "No child processes"),
Error::ESRCH => write!(f, "No such process"),
Error::EIO => write!(f, "Input/output error"),
}
}
}
/// Kernel result type
pub type Result<T> = core::result::Result<T, Error>;
/// Convert from various error types
impl From<()> for Error {
fn from(_: ()) -> Self {
Error::Generic
}
}
impl From<core::alloc::AllocError> for Error {
fn from(_: core::alloc::AllocError) -> Self {
Error::OutOfMemory
}
}

312
kernel/src/fs/advanced.rs Archivo normal
Ver fichero

@@ -0,0 +1,312 @@
// SPDX-License-Identifier: GPL-2.0
//! Advanced file system operations and utilities
use crate::error::{Error, Result};
use crate::fs::file::File;
use crate::fs::inode::Inode;
use crate::fs::dentry::Dentry;
use alloc::string::String;
use alloc::vec::Vec;
use spin::Mutex;
use alloc::sync::Arc;
/// File system statistics
#[derive(Debug, Clone)]
pub struct FsStats {
pub total_inodes: u64,
pub free_inodes: u64,
pub total_blocks: u64,
pub free_blocks: u64,
pub block_size: u32,
pub max_filename_len: u32,
pub filesystem_type: String,
}
/// Directory entry information
#[derive(Debug, Clone)]
pub struct DirEntry {
pub name: String,
pub inode_number: u64,
pub file_type: u8,
}
/// File system operations
pub struct AdvancedFsOps;
impl AdvancedFsOps {
/// Create a new file with specified permissions
pub fn create_file(path: &str, mode: u32) -> Result<Arc<File>> {
crate::info!("Creating file: {} with mode: {:o}", path, mode);
// Parse path and get parent directory
let (parent_path, filename) = split_path(path)?;
// Get parent directory inode
let parent_inode = crate::fs::path::path_lookup(parent_path)?;
// Create new inode for file
let new_inode = crate::fs::inode::alloc_inode()?;
new_inode.set_mode(mode | crate::fs::mode::S_IFREG);
new_inode.set_size(0);
// Create dentry
let dentry = Arc::new(Dentry::new(filename.to_string(), new_inode.clone()));
// Add to parent directory
parent_inode.add_child(dentry)?;
// Create file handle
let file = Arc::new(File::new(new_inode, crate::fs::file::O_RDWR));
Ok(file)
}
/// Create a new directory
pub fn create_directory(path: &str, mode: u32) -> Result<()> {
crate::info!("Creating directory: {} with mode: {:o}", path, mode);
let (parent_path, dirname) = split_path(path)?;
let parent_inode = crate::fs::path::path_lookup(parent_path)?;
// Create new inode for directory
let new_inode = crate::fs::inode::alloc_inode()?;
new_inode.set_mode(mode | crate::fs::mode::S_IFDIR);
new_inode.set_size(0);
// Create dentry
let dentry = Arc::new(Dentry::new(dirname.to_string(), new_inode.clone()));
// Add to parent directory
parent_inode.add_child(dentry)?;
Ok(())
}
/// Remove a file or directory
pub fn remove_path(path: &str) -> Result<()> {
crate::info!("Removing path: {}", path);
let (parent_path, filename) = split_path(path)?;
let parent_inode = crate::fs::path::path_lookup(parent_path)?;
// Find and remove the child
parent_inode.remove_child(filename)?;
Ok(())
}
/// List directory contents
pub fn list_directory(path: &str) -> Result<Vec<DirEntry>> {
let inode = crate::fs::path::path_lookup(path)?;
if !inode.is_dir() {
return Err(Error::ENOTDIR);
}
let mut entries = Vec::new();
// Add . and .. entries
entries.push(DirEntry {
name: ".".to_string(),
inode_number: inode.get_ino(),
file_type: crate::fs::mode::DT_DIR,
});
if let Some(parent) = inode.get_parent() {
entries.push(DirEntry {
name: "..".to_string(),
inode_number: parent.get_ino(),
file_type: crate::fs::mode::DT_DIR,
});
}
// Add actual directory entries
for child in inode.get_children() {
let file_type = if child.inode.is_dir() {
crate::fs::mode::DT_DIR
} else {
crate::fs::mode::DT_REG
};
entries.push(DirEntry {
name: child.name.clone(),
inode_number: child.inode.get_ino(),
file_type,
});
}
Ok(entries)
}
/// Get file/directory statistics
pub fn get_stats(path: &str) -> Result<crate::fs::inode::Stat> {
let inode = crate::fs::path::path_lookup(path)?;
Ok(inode.get_stat())
}
/// Get file system statistics
pub fn get_fs_stats(path: &str) -> Result<FsStats> {
let _inode = crate::fs::path::path_lookup(path)?;
// Return simplified stats
Ok(FsStats {
total_inodes: 1000000,
free_inodes: 999000,
total_blocks: 1000000,
free_blocks: 900000,
block_size: 4096,
max_filename_len: 255,
filesystem_type: "RustFS".to_string(),
})
}
/// Copy file
pub fn copy_file(src: &str, dst: &str) -> Result<()> {
crate::info!("Copying file from {} to {}", src, dst);
// Open source file
let src_inode = crate::fs::path::path_lookup(src)?;
if src_inode.is_dir() {
return Err(Error::EISDIR);
}
// Read source file data
let mut buffer = vec![0u8; src_inode.get_size() as usize];
src_inode.read_at(0, &mut buffer)?;
// Create destination file
let dst_file = Self::create_file(dst, 0o644)?;
// Write data to destination
dst_file.write(&buffer)?;
Ok(())
}
/// Move/rename file
pub fn move_file(src: &str, dst: &str) -> Result<()> {
crate::info!("Moving file from {} to {}", src, dst);
// Copy file
Self::copy_file(src, dst)?;
// Remove source
Self::remove_path(src)?;
Ok(())
}
/// Create symbolic link
pub fn create_symlink(target: &str, link: &str) -> Result<()> {
crate::info!("Creating symlink: {} -> {}", link, target);
let (parent_path, linkname) = split_path(link)?;
let parent_inode = crate::fs::path::path_lookup(parent_path)?;
// Create new inode for symlink
let new_inode = crate::fs::inode::alloc_inode()?;
new_inode.set_mode(0o777 | crate::fs::mode::S_IFLNK);
new_inode.set_size(target.len() as u64);
// Store target path in inode data
new_inode.write_at(0, target.as_bytes())?;
// Create dentry
let dentry = Arc::new(Dentry::new(linkname.to_string(), new_inode.clone()));
// Add to parent directory
parent_inode.add_child(dentry)?;
Ok(())
}
/// Create hard link
pub fn create_hardlink(target: &str, link: &str) -> Result<()> {
crate::info!("Creating hardlink: {} -> {}", link, target);
let target_inode = crate::fs::path::path_lookup(target)?;
let (parent_path, linkname) = split_path(link)?;
let parent_inode = crate::fs::path::path_lookup(parent_path)?;
// Create dentry pointing to existing inode
let dentry = Arc::new(Dentry::new(linkname.to_string(), target_inode.clone()));
// Add to parent directory
parent_inode.add_child(dentry)?;
// Increment link count
target_inode.inc_nlink();
Ok(())
}
}
/// Split path into parent and filename
fn split_path(path: &str) -> Result<(&str, &str)> {
if path == "/" {
return Err(Error::EINVAL);
}
let path = path.trim_end_matches('/');
if let Some(pos) = path.rfind('/') {
let parent = if pos == 0 { "/" } else { &path[..pos] };
let filename = &path[pos + 1..];
Ok((parent, filename))
} else {
Ok(("/", path))
}
}
/// File system utility functions
pub mod utils {
use super::*;
/// Check if path exists
pub fn path_exists(path: &str) -> bool {
crate::fs::path::path_lookup(path).is_ok()
}
/// Check if path is a directory
pub fn is_directory(path: &str) -> bool {
if let Ok(inode) = crate::fs::path::path_lookup(path) {
inode.is_dir()
} else {
false
}
}
/// Check if path is a regular file
pub fn is_regular_file(path: &str) -> bool {
if let Ok(inode) = crate::fs::path::path_lookup(path) {
inode.is_file()
} else {
false
}
}
/// Get file size
pub fn get_file_size(path: &str) -> Result<u64> {
let inode = crate::fs::path::path_lookup(path)?;
Ok(inode.get_size())
}
/// Get file permissions
pub fn get_file_mode(path: &str) -> Result<u32> {
let inode = crate::fs::path::path_lookup(path)?;
Ok(inode.get_mode())
}
/// Set file permissions
pub fn set_file_mode(path: &str, mode: u32) -> Result<()> {
let inode = crate::fs::path::path_lookup(path)?;
inode.set_mode(mode);
Ok(())
}
}
/// Initialize advanced file system operations
pub fn init() -> Result<()> {
crate::info!("Advanced file system operations initialized");
Ok(())
}

284
kernel/src/fs/dentry.rs Archivo normal
Ver fichero

@@ -0,0 +1,284 @@
// SPDX-License-Identifier: GPL-2.0
//! Directory entry (dentry) abstraction - Linux compatible
use alloc::{format, string::String, vec::Vec}; // Add format macro
use core::sync::atomic::{AtomicU32, Ordering};
use crate::error::Result;
use crate::sync::{Arc, Mutex};
/// Dentry structure - similar to Linux struct dentry
#[derive(Debug)]
pub struct Dentry {
/// Entry name
pub d_name: String,
/// Associated inode
pub d_inode: Option<Arc<super::Inode>>,
/// Parent dentry
pub d_parent: Option<Arc<Dentry>>,
/// Child entries (for directories)
pub d_subdirs: Mutex<Vec<Arc<Dentry>>>,
/// Dentry operations
pub d_op: Option<Arc<dyn DentryOperations>>,
/// Superblock
pub d_sb: Option<Arc<super::SuperBlock>>,
/// Reference count
pub d_count: AtomicU32,
/// Dentry flags
pub d_flags: AtomicU32,
/// Hash for dcache
pub d_hash: u32,
}
impl Dentry {
/// Create a new dentry
pub fn new(name: String, inode: Option<Arc<super::Inode>>) -> Self {
Self {
d_name: name,
d_inode: inode,
d_parent: None,
d_subdirs: Mutex::new(Vec::new()),
d_op: None,
d_sb: None,
d_count: AtomicU32::new(1),
d_flags: AtomicU32::new(0),
d_hash: 0, // TODO: Calculate hash
}
}
/// Set parent dentry
pub fn set_parent(&mut self, parent: Arc<Dentry>) {
self.d_parent = Some(parent);
}
/// Add child dentry
pub fn add_child(&self, child: Arc<Dentry>) {
let mut subdirs = self.d_subdirs.lock();
subdirs.push(child);
}
/// Find child dentry by name
pub fn find_child(&self, name: &str) -> Option<Arc<Dentry>> {
let subdirs = self.d_subdirs.lock();
for child in subdirs.iter() {
if child.d_name == name {
return Some(child.clone());
}
}
None
}
/// Get full path of this dentry
pub fn get_path(&self) -> String {
if let Some(ref parent) = self.d_parent {
if parent.d_name == "/" {
format!("/{}", self.d_name)
} else {
format!("{}/{}", parent.get_path(), self.d_name)
}
} else {
self.d_name.clone()
}
}
/// Check if dentry is root
pub fn is_root(&self) -> bool {
self.d_parent.is_none() || self.d_name == "/"
}
/// Increment reference count
pub fn dget(&self) {
self.d_count.fetch_add(1, Ordering::Relaxed);
}
/// Decrement reference count
pub fn dput(&self) {
let old_count = self.d_count.fetch_sub(1, Ordering::Relaxed);
if old_count == 1 {
// Last reference, dentry should be cleaned up
// TODO: Call d_delete operation if present
}
}
/// Revalidate dentry
pub fn revalidate(&self) -> Result<bool> {
if let Some(ref ops) = self.d_op {
ops.revalidate(self)
} else {
Ok(true) // Always valid by default
}
}
/// Delete dentry
pub fn delete(&self) -> Result<()> {
if let Some(ref ops) = self.d_op {
ops.delete(self)
} else {
Ok(())
}
}
/// Compare two dentries
pub fn compare(&self, other: &Dentry) -> Result<bool> {
if let Some(ref ops) = self.d_op {
ops.compare(self, other)
} else {
Ok(self.d_name == other.d_name)
}
}
/// Hash dentry name
pub fn hash(&self) -> Result<u32> {
if let Some(ref ops) = self.d_op {
ops.hash(self)
} else {
// Simple hash function
let mut hash = 0u32;
for byte in self.d_name.bytes() {
hash = hash.wrapping_mul(31).wrapping_add(byte as u32);
}
Ok(hash)
}
}
}
unsafe impl Send for Dentry {}
unsafe impl Sync for Dentry {}
/// Dentry operations trait - similar to Linux dentry_operations
pub trait DentryOperations: Send + Sync + core::fmt::Debug {
/// Revalidate dentry
fn revalidate(&self, dentry: &Dentry) -> Result<bool>;
/// Hash dentry name
fn hash(&self, dentry: &Dentry) -> Result<u32>;
/// Compare two dentries
fn compare(&self, d1: &Dentry, d2: &Dentry) -> Result<bool>;
/// Delete dentry
fn delete(&self, dentry: &Dentry) -> Result<()>;
/// Release dentry
fn release(&self, dentry: &Dentry) -> Result<()>;
/// Canonicalize path
fn canonical_path(&self, dentry: &Dentry) -> Result<String>;
}
/// Generic dentry operations
#[derive(Debug)]
pub struct GenericDentryOps;
impl DentryOperations for GenericDentryOps {
fn revalidate(&self, dentry: &Dentry) -> Result<bool> {
Ok(true)
}
fn hash(&self, dentry: &Dentry) -> Result<u32> {
dentry.hash()
}
fn compare(&self, d1: &Dentry, d2: &Dentry) -> Result<bool> {
Ok(d1.d_name == d2.d_name)
}
fn delete(&self, dentry: &Dentry) -> Result<()> {
Ok(())
}
fn release(&self, dentry: &Dentry) -> Result<()> {
Ok(())
}
fn canonical_path(&self, dentry: &Dentry) -> Result<String> {
Ok(dentry.get_path())
}
}
/// Dentry cache (dcache) - simplified version
pub struct DentryCache {
/// Cached dentries
cache: Mutex<alloc::collections::BTreeMap<String, Arc<Dentry>>>,
/// Hash buckets for faster lookup
hash_table: Vec<Mutex<Vec<Arc<Dentry>>>>,
}
impl DentryCache {
/// Create a new dentry cache
pub fn new() -> Self {
const HASH_BUCKETS: usize = 256;
let mut hash_table = Vec::with_capacity(HASH_BUCKETS);
for _ in 0..HASH_BUCKETS {
hash_table.push(Mutex::new(Vec::new()));
}
Self {
cache: Mutex::new(alloc::collections::BTreeMap::new()),
hash_table,
}
}
/// Look up dentry by path
pub fn lookup(&self, path: &str) -> Option<Arc<Dentry>> {
let cache = self.cache.lock();
cache.get(path).cloned()
}
/// Insert dentry into cache
pub fn insert(&self, path: String, dentry: Arc<Dentry>) {
let mut cache = self.cache.lock();
cache.insert(path, dentry.clone());
// Also insert into hash table
let hash = dentry.d_hash as usize % self.hash_table.len();
let mut bucket = self.hash_table[hash].lock();
bucket.push(dentry);
}
/// Remove dentry from cache
pub fn remove(&self, path: &str) -> Option<Arc<Dentry>> {
let mut cache = self.cache.lock();
cache.remove(path)
}
/// Prune unused dentries
pub fn prune(&self) {
let mut cache = self.cache.lock();
cache.retain(|_, dentry| dentry.d_count.load(Ordering::Relaxed) > 1);
// Also prune hash table
for bucket in &self.hash_table {
let mut bucket = bucket.lock();
bucket.retain(|dentry| dentry.d_count.load(Ordering::Relaxed) > 1);
}
}
}
/// Global dentry cache
static DCACHE: spin::once::Once<DentryCache> = spin::once::Once::new();
fn get_dcache() -> &'static DentryCache {
DCACHE.call_once(|| DentryCache::new())
}
/// Look up dentry in cache
pub fn dcache_lookup(path: &str) -> Option<Arc<Dentry>> {
get_dcache().lookup(path)
}
/// Insert dentry into cache
pub fn dcache_insert(path: String, dentry: Arc<Dentry>) {
get_dcache().insert(path, dentry);
}
/// Remove dentry from cache
pub fn dcache_remove(path: &str) -> Option<Arc<Dentry>> {
get_dcache().remove(path)
}
/// Prune dentry cache
pub fn dcache_prune() {
get_dcache().prune();
}

454
kernel/src/fs/devfs.rs Archivo normal
Ver fichero

@@ -0,0 +1,454 @@
// SPDX-License-Identifier: GPL-2.0
//! Character device filesystem integration
//!
//! This driver provides VFS integration for character devices
//! like /dev/null, /dev/zero, /dev/random, etc.
use alloc::{boxed::Box, string::String, vec};
use crate::error::{Error, Result};
use crate::fs::*;
use crate::memory::UserSlicePtr;
use crate::sync::Arc; // Import vec macro and Box
/// Character device file operations
#[derive(Debug)]
pub struct CharDevFileOps {
/// Device operations
dev_ops: Option<Arc<dyn CharDevOperations>>,
}
impl CharDevFileOps {
pub fn new(dev_ops: Option<Arc<dyn CharDevOperations>>) -> Self {
Self { dev_ops }
}
}
impl FileOperations for CharDevFileOps {
fn read(&self, file: &File, buf: UserSlicePtr, count: usize) -> Result<isize> {
if let Some(ref ops) = self.dev_ops {
ops.read(file, buf, count)
} else {
Err(Error::ENODEV)
}
}
fn write(&self, file: &File, buf: UserSlicePtr, count: usize) -> Result<isize> {
if let Some(ref ops) = self.dev_ops {
ops.write(file, buf, count)
} else {
Err(Error::ENODEV)
}
}
fn seek(&self, file: &File, offset: i64, whence: i32) -> Result<i64> {
// Most character devices don't support seeking
Err(Error::ESPIPE)
}
fn ioctl(&self, file: &File, cmd: u32, arg: usize) -> Result<isize> {
if let Some(ref ops) = self.dev_ops {
ops.ioctl(file, cmd, arg)
} else {
Err(Error::ENOTTY)
}
}
fn mmap(&self, file: &File, vma: &mut crate::memory::VmaArea) -> Result<()> {
if let Some(ref ops) = self.dev_ops {
ops.mmap(file, vma)
} else {
Err(Error::ENODEV)
}
}
fn fsync(&self, file: &File, datasync: bool) -> Result<()> {
// Character devices don't need syncing
Ok(())
}
fn poll(&self, file: &File, wait: &mut PollWait) -> Result<u32> {
if let Some(ref ops) = self.dev_ops {
ops.poll(file, wait)
} else {
Ok(POLLIN | POLLOUT)
}
}
fn open(&self, inode: &Inode, file: &File) -> Result<()> {
if let Some(ref ops) = self.dev_ops {
ops.open(inode, file)
} else {
Ok(())
}
}
fn release(&self, inode: &Inode, file: &File) -> Result<()> {
if let Some(ref ops) = self.dev_ops {
ops.release(inode, file)
} else {
Ok(())
}
}
}
/// Character device operations trait
pub trait CharDevOperations: Send + Sync + core::fmt::Debug {
fn read(&self, file: &File, buf: UserSlicePtr, count: usize) -> Result<isize>;
fn write(&self, file: &File, buf: UserSlicePtr, count: usize) -> Result<isize>;
fn ioctl(&self, file: &File, cmd: u32, arg: usize) -> Result<isize>;
fn mmap(&self, file: &File, vma: &mut crate::memory::VmaArea) -> Result<()>;
fn poll(&self, file: &File, wait: &mut PollWait) -> Result<u32>;
fn open(&self, inode: &Inode, file: &File) -> Result<()>;
fn release(&self, inode: &Inode, file: &File) -> Result<()>;
}
/// /dev/null device operations
#[derive(Debug)]
pub struct NullDevOps;
impl CharDevOperations for NullDevOps {
fn read(&self, _file: &File, _buf: UserSlicePtr, _count: usize) -> Result<isize> {
Ok(0) // EOF
}
fn write(&self, _file: &File, _buf: UserSlicePtr, count: usize) -> Result<isize> {
Ok(count as isize) // Discard all data
}
fn ioctl(&self, _file: &File, _cmd: u32, _arg: usize) -> Result<isize> {
Err(Error::ENOTTY)
}
fn mmap(&self, _file: &File, _vma: &mut crate::memory::VmaArea) -> Result<()> {
Err(Error::ENODEV)
}
fn poll(&self, _file: &File, _wait: &mut PollWait) -> Result<u32> {
Ok(POLLIN | POLLOUT) // Always ready
}
fn open(&self, _inode: &Inode, _file: &File) -> Result<()> {
Ok(())
}
fn release(&self, _inode: &Inode, _file: &File) -> Result<()> {
Ok(())
}
}
/// /dev/zero device operations
#[derive(Debug)]
pub struct ZeroDevOps;
impl CharDevOperations for ZeroDevOps {
fn read(&self, _file: &File, buf: UserSlicePtr, count: usize) -> Result<isize> {
// Fill buffer with zeros
let zeros = vec![0u8; count];
buf.copy_from_slice(&zeros)?;
Ok(count as isize)
}
fn write(&self, _file: &File, _buf: UserSlicePtr, count: usize) -> Result<isize> {
Ok(count as isize) // Discard all data
}
fn ioctl(&self, _file: &File, _cmd: u32, _arg: usize) -> Result<isize> {
Err(Error::ENOTTY)
}
fn mmap(&self, _file: &File, _vma: &mut crate::memory::VmaArea) -> Result<()> {
// TODO: Map zero page
Err(Error::ENODEV)
}
fn poll(&self, _file: &File, _wait: &mut PollWait) -> Result<u32> {
Ok(POLLIN | POLLOUT) // Always ready
}
fn open(&self, _inode: &Inode, _file: &File) -> Result<()> {
Ok(())
}
fn release(&self, _inode: &Inode, _file: &File) -> Result<()> {
Ok(())
}
}
/// /dev/full device operations
#[derive(Debug)]
pub struct FullDevOps;
impl CharDevOperations for FullDevOps {
fn read(&self, _file: &File, buf: UserSlicePtr, count: usize) -> Result<isize> {
// Fill buffer with zeros (like /dev/zero)
let zeros = vec![0u8; count];
buf.copy_from_slice(&zeros)?;
Ok(count as isize)
}
fn write(&self, _file: &File, _buf: UserSlicePtr, _count: usize) -> Result<isize> {
Err(Error::ENOSPC) // No space left on device
}
fn ioctl(&self, _file: &File, _cmd: u32, _arg: usize) -> Result<isize> {
Err(Error::ENOTTY)
}
fn mmap(&self, _file: &File, _vma: &mut crate::memory::VmaArea) -> Result<()> {
Err(Error::ENODEV)
}
fn poll(&self, _file: &File, _wait: &mut PollWait) -> Result<u32> {
Ok(POLLIN) // Only readable
}
fn open(&self, _inode: &Inode, _file: &File) -> Result<()> {
Ok(())
}
fn release(&self, _inode: &Inode, _file: &File) -> Result<()> {
Ok(())
}
}
/// /dev/random device operations (simplified)
#[derive(Debug)]
pub struct RandomDevOps;
impl CharDevOperations for RandomDevOps {
fn read(&self, _file: &File, buf: UserSlicePtr, count: usize) -> Result<isize> {
// Generate pseudo-random data
// TODO: Use proper random number generator
let mut random_data = vec![0u8; count];
for i in 0..count {
random_data[i] = (i * 37 + 13) as u8; // Very simple PRNG
}
buf.copy_from_slice(&random_data)?;
Ok(count as isize)
}
fn write(&self, _file: &File, _buf: UserSlicePtr, count: usize) -> Result<isize> {
// TODO: Add entropy to random pool
Ok(count as isize)
}
fn ioctl(&self, _file: &File, _cmd: u32, _arg: usize) -> Result<isize> {
// TODO: Implement random device ioctls
Err(Error::ENOTTY)
}
fn mmap(&self, _file: &File, _vma: &mut crate::memory::VmaArea) -> Result<()> {
Err(Error::ENODEV)
}
fn poll(&self, _file: &File, _wait: &mut PollWait) -> Result<u32> {
Ok(POLLIN | POLLOUT) // Always ready
}
fn open(&self, _inode: &Inode, _file: &File) -> Result<()> {
Ok(())
}
fn release(&self, _inode: &Inode, _file: &File) -> Result<()> {
Ok(())
}
}
/// Create a character device inode
pub fn create_char_device_inode(
major: u32,
minor: u32,
mode: u32,
ops: Arc<dyn CharDevOperations>,
) -> Arc<Inode> {
let mut inode = Inode::new(0, mode::S_IFCHR | mode);
inode.i_rdev = crate::device::DeviceNumber::new(major, minor);
inode.set_file_operations(Arc::new(CharDevFileOps::new(Some(ops))));
Arc::new(inode)
}
/// DevFS - device filesystem for /dev
pub struct DevFs {
/// Device entries
devices: crate::sync::Mutex<alloc::collections::BTreeMap<String, Arc<Inode>>>,
}
impl DevFs {
pub fn new() -> Self {
let mut devfs = Self {
devices: crate::sync::Mutex::new(alloc::collections::BTreeMap::new()),
};
devfs.create_standard_devices();
devfs
}
fn create_standard_devices(&mut self) {
// Create /dev/null
let null_inode = create_char_device_inode(1, 3, 0o666, Arc::new(NullDevOps));
self.add_device("null", null_inode);
// Create /dev/zero
let zero_inode = create_char_device_inode(1, 5, 0o666, Arc::new(ZeroDevOps));
self.add_device("zero", zero_inode);
// Create /dev/full
let full_inode = create_char_device_inode(1, 7, 0o666, Arc::new(FullDevOps));
self.add_device("full", full_inode);
// Create /dev/random
let random_inode = create_char_device_inode(1, 8, 0o666, Arc::new(RandomDevOps));
self.add_device("random", random_inode);
// Create /dev/urandom (same as random for now)
let urandom_inode = create_char_device_inode(1, 9, 0o666, Arc::new(RandomDevOps));
self.add_device("urandom", urandom_inode);
}
pub fn add_device(&mut self, name: &str, inode: Arc<Inode>) {
let mut devices = self.devices.lock();
devices.insert(String::from(name), inode);
}
pub fn get_device(&self, name: &str) -> Option<Arc<Inode>> {
let devices = self.devices.lock();
devices.get(name).cloned()
}
pub fn list_devices(&self) -> alloc::vec::Vec<String> {
let devices = self.devices.lock();
devices.keys().cloned().collect()
}
}
/// DevFS inode operations
#[derive(Debug)]
pub struct DevFsInodeOps {
devfs: *const DevFs,
}
impl DevFsInodeOps {
pub fn new(devfs: &DevFs) -> Self {
Self {
devfs: devfs as *const DevFs,
}
}
fn get_devfs(&self) -> &DevFs {
unsafe { &*self.devfs }
}
}
unsafe impl Send for DevFsInodeOps {}
unsafe impl Sync for DevFsInodeOps {}
impl InodeOperations for DevFsInodeOps {
fn lookup(&self, dir: &Inode, name: &str) -> Result<Arc<Inode>> {
let devfs = self.get_devfs();
devfs.get_device(name).ok_or(Error::ENOENT)
}
fn create(&self, dir: &Inode, name: &str, mode: u32) -> Result<Arc<Inode>> {
Err(Error::EPERM) // Can't create devices in /dev directly
}
fn mkdir(&self, dir: &Inode, name: &str, mode: u32) -> Result<Arc<Inode>> {
Err(Error::EPERM)
}
fn unlink(&self, dir: &Inode, name: &str) -> Result<()> {
Err(Error::EPERM)
}
fn rmdir(&self, dir: &Inode, name: &str) -> Result<()> {
Err(Error::EPERM)
}
fn symlink(&self, dir: &Inode, name: &str, target: &str) -> Result<Arc<Inode>> {
Err(Error::EPERM)
}
fn rename(
&self,
old_dir: &Inode,
old_name: &str,
new_dir: &Inode,
new_name: &str,
) -> Result<()> {
Err(Error::EPERM)
}
fn setattr(&self, inode: &Inode, attr: &InodeAttr) -> Result<()> {
Err(Error::EPERM)
}
fn getattr(&self, inode: &Inode) -> Result<InodeAttr> {
let generic_ops = GenericInodeOps;
generic_ops.getattr(inode)
}
fn readlink(&self, inode: &Inode) -> Result<String> {
Err(Error::EINVAL)
}
fn follow_link(&self, inode: &Inode) -> Result<Arc<Inode>> {
Err(Error::EINVAL)
}
fn truncate(&self, inode: &Inode, size: u64) -> Result<()> {
Err(Error::EPERM)
}
fn getxattr(&self, inode: &Inode, name: &str) -> Result<alloc::vec::Vec<u8>> {
Err(Error::ENODATA)
}
fn setxattr(&self, inode: &Inode, name: &str, value: &[u8], flags: u32) -> Result<()> {
Err(Error::EPERM)
}
fn listxattr(&self, inode: &Inode) -> Result<alloc::vec::Vec<String>> {
Ok(alloc::vec::Vec::new())
}
fn removexattr(&self, inode: &Inode, name: &str) -> Result<()> {
Err(Error::EPERM)
}
}
/// Mount devfs
pub fn mount_devfs(_dev_name: &str, _flags: u32, _data: Option<&str>) -> Result<Arc<SuperBlock>> {
let mut sb = SuperBlock::new("devfs")?;
sb.s_magic = 0x1373; // DEVFS magic
let devfs = Box::leak(Box::new(DevFs::new()));
sb.s_fs_info = Some(devfs as *mut DevFs as *mut u8);
// Create root inode
let root_inode = Arc::new({
let mut inode = Inode::new(1, mode::S_IFDIR | 0o755);
inode.set_operations(Arc::new(DevFsInodeOps::new(devfs)));
inode
});
let root_dentry = Arc::new(Dentry::new(String::from("/"), Some(root_inode)));
sb.s_root = Some(root_dentry);
Ok(Arc::new(sb))
}
/// Register devfs filesystem
pub fn register_devfs() -> Result<()> {
let devfs_type = FileSystemType::new(
String::from("devfs"),
|_fstype, flags, _dev_name, data| mount_devfs(_dev_name, flags, data),
|_sb| Ok(()),
);
// TODO: Register with VFS
crate::console::print_info("Registered devfs filesystem\n");
Ok(())
}

273
kernel/src/fs/file.rs Archivo normal
Ver fichero

@@ -0,0 +1,273 @@
// SPDX-License-Identifier: GPL-2.0
//! File abstraction - Linux compatible
use alloc::string::String;
use core::sync::atomic::{AtomicI64, AtomicU32, Ordering};
use crate::error::{Error, Result};
// use crate::types::*; // Commented out - unused for now
use crate::memory::UserSlicePtr; // Remove UserPtr since it's unused
use crate::sync::Arc; // Remove Mutex and RwLock since they're unused
/// File structure - similar to Linux struct file
#[derive(Debug)]
pub struct File {
/// File operations
pub f_op: Option<Arc<dyn FileOperations>>,
/// Current file position
pub pos: AtomicI64,
/// File flags
pub flags: AtomicU32,
/// File mode
pub mode: u32,
/// Associated inode
pub inode: Option<Arc<super::Inode>>,
/// Associated dentry
pub dentry: Option<Arc<super::Dentry>>,
/// Private data for file operations
pub private_data: Option<*mut u8>,
/// File path (for debugging/proc)
pub path: String,
/// Reference count
pub refcount: AtomicU32,
}
impl File {
/// Create a new file
pub fn new(path: &str, flags: u32, mode: u32) -> Result<Self> {
Ok(Self {
f_op: None,
pos: AtomicI64::new(0),
flags: AtomicU32::new(flags),
mode,
inode: None,
dentry: None,
private_data: None,
path: String::from(path),
refcount: AtomicU32::new(1),
})
}
/// Set file operations
pub fn set_operations(&mut self, ops: Arc<dyn FileOperations>) {
self.f_op = Some(ops);
}
/// Read from file
pub fn read(&self, buf: UserSlicePtr, count: usize) -> Result<isize> {
if let Some(ref ops) = self.f_op {
ops.read(self, buf, count)
} else {
Err(Error::ENOSYS)
}
}
/// Write to file
pub fn write(&self, buf: UserSlicePtr, count: usize) -> Result<isize> {
if let Some(ref ops) = self.f_op {
ops.write(self, buf, count)
} else {
Err(Error::ENOSYS)
}
}
/// Seek within file
pub fn seek(&self, offset: i64, whence: i32) -> Result<i64> {
if let Some(ref ops) = self.f_op {
let new_pos = ops.seek(self, offset, whence)?;
self.pos.store(new_pos, Ordering::Relaxed);
Ok(new_pos)
} else {
Err(Error::ENOSYS)
}
}
/// Get file status
pub fn stat(&self) -> Result<super::KStat> {
if let Some(ref inode) = self.inode {
inode.stat()
} else {
// Create a basic stat structure
Ok(super::KStat {
st_dev: 0,
st_ino: 0,
st_nlink: 1,
st_mode: self.mode,
st_uid: 0,
st_gid: 0,
st_rdev: 0,
st_size: 0,
st_blksize: 4096,
st_blocks: 0,
st_atime: 0,
st_atime_nsec: 0,
st_mtime: 0,
st_mtime_nsec: 0,
st_ctime: 0,
st_ctime_nsec: 0,
})
}
}
/// Perform ioctl operation
pub fn ioctl(&self, cmd: u32, arg: usize) -> Result<isize> {
if let Some(ref ops) = self.f_op {
ops.ioctl(self, cmd, arg)
} else {
Err(Error::ENOTTY)
}
}
/// Memory map file
pub fn mmap(&self, vma: &mut crate::memory::VmaArea) -> Result<()> {
if let Some(ref ops) = self.f_op {
ops.mmap(self, vma)
} else {
Err(Error::ENODEV)
}
}
/// Sync file to storage
pub fn fsync(&self, datasync: bool) -> Result<()> {
if let Some(ref ops) = self.f_op {
ops.fsync(self, datasync)
} else {
Ok(()) // No-op for files without sync
}
}
/// Poll file for events
pub fn poll(&self, wait: &mut super::PollWait) -> Result<u32> {
if let Some(ref ops) = self.f_op {
ops.poll(self, wait)
} else {
Ok(super::POLLIN | super::POLLOUT) // Always ready
}
}
/// Get current file position
pub fn get_pos(&self) -> i64 {
self.pos.load(Ordering::Relaxed)
}
/// Set file position
pub fn set_pos(&self, pos: i64) {
self.pos.store(pos, Ordering::Relaxed);
}
/// Get file flags
pub fn get_flags(&self) -> u32 {
self.flags.load(Ordering::Relaxed)
}
/// Check if file is readable
pub fn is_readable(&self) -> bool {
let flags = self.get_flags();
(flags & super::flags::O_ACCMODE) != super::flags::O_WRONLY
}
/// Check if file is writable
pub fn is_writable(&self) -> bool {
let flags = self.get_flags();
(flags & super::flags::O_ACCMODE) != super::flags::O_RDONLY
}
/// Increment reference count
pub fn get_file(&self) -> Result<()> {
self.refcount.fetch_add(1, Ordering::Relaxed);
Ok(())
}
/// Decrement reference count (fput equivalent)
pub fn put_file(&self) -> Result<()> {
let old_count = self.refcount.fetch_sub(1, Ordering::Relaxed);
if old_count == 1 {
// Last reference, file should be cleaned up
// TODO: Call release operation if present
}
Ok(())
}
}
unsafe impl Send for File {}
unsafe impl Sync for File {}
/// File operations trait - similar to Linux file_operations
pub trait FileOperations: Send + Sync + core::fmt::Debug {
/// Read from file
fn read(&self, file: &File, buf: UserSlicePtr, count: usize) -> Result<isize>;
/// Write to file
fn write(&self, file: &File, buf: UserSlicePtr, count: usize) -> Result<isize>;
/// Seek within file
fn seek(&self, file: &File, offset: i64, whence: i32) -> Result<i64>;
/// I/O control
fn ioctl(&self, file: &File, cmd: u32, arg: usize) -> Result<isize>;
/// Memory map
fn mmap(&self, file: &File, vma: &mut crate::memory::VmaArea) -> Result<()>;
/// Sync file
fn fsync(&self, file: &File, datasync: bool) -> Result<()>;
/// Poll for events
fn poll(&self, file: &File, wait: &mut super::PollWait) -> Result<u32>;
/// Open file (optional)
fn open(&self, inode: &super::Inode, file: &File) -> Result<()> {
Ok(())
}
/// Release file (optional)
fn release(&self, inode: &super::Inode, file: &File) -> Result<()> {
Ok(())
}
/// Flush file (optional)
fn flush(&self, file: &File) -> Result<()> {
Ok(())
}
/// Lock file (optional)
fn lock(&self, file: &File, cmd: i32) -> Result<()> {
Err(Error::ENOSYS)
}
/// Read directory entries (optional)
fn readdir(&self, file: &File, ctx: &mut super::DirContext) -> Result<()> {
Err(Error::ENOTDIR)
}
}
/// Directory context for readdir operations
pub struct DirContext {
/// Current position in directory
pub pos: i64,
/// Entries collected so far
pub entries: alloc::vec::Vec<super::DirEntry>,
}
impl DirContext {
pub fn new(pos: i64) -> Self {
Self {
pos,
entries: alloc::vec::Vec::new(),
}
}
/// Add a directory entry
pub fn add_entry(&mut self, ino: u64, name: &str, d_type: u8) {
let entry = super::DirEntry {
ino,
off: self.pos,
reclen: (core::mem::size_of::<super::DirEntry>() + name.len() + 1) as u16,
name: String::from(name),
d_type,
};
self.entries.push(entry);
self.pos += 1;
}
}

435
kernel/src/fs/inode.rs Archivo normal
Ver fichero

@@ -0,0 +1,435 @@
// SPDX-License-Identifier: GPL-2.0
//! Inode abstraction - Linux compatible
use alloc::string::String;
use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};
use crate::device::DeviceNumber;
use crate::error::{Error, Result};
use crate::sync::{Arc, Mutex};
use crate::time::{get_current_time, TimeSpec};
/// Inode structure - similar to Linux struct inode
#[derive(Debug)]
pub struct Inode {
/// Inode number
pub i_ino: u64,
/// File mode and type
pub i_mode: AtomicU32,
/// Number of hard links
pub i_nlink: AtomicU32,
/// User ID
pub i_uid: AtomicU32,
/// Group ID
pub i_gid: AtomicU32,
/// Device number (for device files)
pub i_rdev: DeviceNumber,
/// File size
pub i_size: AtomicU64,
/// Block size
pub i_blksize: u32,
/// Number of blocks
pub i_blocks: AtomicU64,
/// Access time
pub i_atime: Mutex<TimeSpec>,
/// Modification time
pub i_mtime: Mutex<TimeSpec>,
/// Status change time
pub i_ctime: Mutex<TimeSpec>,
/// Inode operations
pub i_op: Option<Arc<dyn InodeOperations>>,
/// File operations (for regular files)
pub i_fop: Option<Arc<dyn super::FileOperations>>,
/// Superblock this inode belongs to
pub i_sb: Option<Arc<super::SuperBlock>>,
/// Private data
pub private_data: Option<*mut u8>,
/// Reference count
pub refcount: AtomicU32,
/// Inode flags
pub i_flags: AtomicU32,
}
impl Inode {
/// Create a new inode
pub fn new(ino: u64, mode: u32) -> Self {
let now = get_current_time();
Self {
i_ino: ino,
i_mode: AtomicU32::new(mode),
i_nlink: AtomicU32::new(1),
i_uid: AtomicU32::new(0),
i_gid: AtomicU32::new(0),
i_rdev: DeviceNumber::new(0, 0),
i_size: AtomicU64::new(0),
i_blksize: 4096,
i_blocks: AtomicU64::new(0),
i_atime: Mutex::new(now),
i_mtime: Mutex::new(now),
i_ctime: Mutex::new(now),
i_op: None,
i_fop: None,
i_sb: None,
private_data: None,
refcount: AtomicU32::new(1),
i_flags: AtomicU32::new(0),
}
}
/// Set inode operations
pub fn set_operations(&mut self, ops: Arc<dyn InodeOperations>) {
self.i_op = Some(ops);
}
/// Set file operations
pub fn set_file_operations(&mut self, ops: Arc<dyn super::FileOperations>) {
self.i_fop = Some(ops);
}
/// Get file statistics
pub fn stat(&self) -> Result<super::KStat> {
let atime = self.i_atime.lock();
let mtime = self.i_mtime.lock();
let ctime = self.i_ctime.lock();
Ok(super::KStat {
st_dev: if let Some(ref sb) = self.i_sb {
sb.s_dev.as_raw()
} else {
0
},
st_ino: self.i_ino,
st_nlink: self.i_nlink.load(Ordering::Relaxed) as u64,
st_mode: self.i_mode.load(Ordering::Relaxed),
st_uid: self.i_uid.load(Ordering::Relaxed),
st_gid: self.i_gid.load(Ordering::Relaxed),
st_rdev: self.i_rdev.as_raw(),
st_size: self.i_size.load(Ordering::Relaxed) as i64,
st_blksize: self.i_blksize as u64,
st_blocks: self.i_blocks.load(Ordering::Relaxed),
st_atime: atime.tv_sec,
st_atime_nsec: atime.tv_nsec,
st_mtime: mtime.tv_sec,
st_mtime_nsec: mtime.tv_nsec,
st_ctime: ctime.tv_sec,
st_ctime_nsec: ctime.tv_nsec,
})
}
/// Check if inode is a regular file
pub fn is_regular(&self) -> bool {
let mode = self.i_mode.load(Ordering::Relaxed);
super::mode::s_isreg(mode)
}
/// Check if inode is a directory
pub fn is_directory(&self) -> bool {
let mode = self.i_mode.load(Ordering::Relaxed);
super::mode::s_isdir(mode)
}
/// Check if inode is a character device
pub fn is_char_device(&self) -> bool {
let mode = self.i_mode.load(Ordering::Relaxed);
super::mode::s_ischr(mode)
}
/// Check if inode is a block device
pub fn is_block_device(&self) -> bool {
let mode = self.i_mode.load(Ordering::Relaxed);
super::mode::s_isblk(mode)
}
/// Update access time
pub fn update_atime(&self) {
let mut atime = self.i_atime.lock();
*atime = get_current_time();
}
/// Update modification time
pub fn update_mtime(&self) {
let mut mtime = self.i_mtime.lock();
*mtime = get_current_time();
}
/// Update status change time
pub fn update_ctime(&self) {
let mut ctime = self.i_ctime.lock();
*ctime = get_current_time();
}
/// Set file size
pub fn set_size(&self, size: u64) {
self.i_size.store(size, Ordering::Relaxed);
self.update_mtime();
self.update_ctime();
}
/// Get file size
pub fn get_size(&self) -> u64 {
self.i_size.load(Ordering::Relaxed)
}
/// Increment reference count
pub fn iget(&self) {
self.refcount.fetch_add(1, Ordering::Relaxed);
}
/// Decrement reference count
pub fn iput(&self) {
let old_count = self.refcount.fetch_sub(1, Ordering::Relaxed);
if old_count == 1 {
// Last reference, inode should be cleaned up
// TODO: Call destroy_inode operation if present
}
}
/// Create a new file in this directory
pub fn create(&self, name: &str, mode: u32) -> Result<Arc<Inode>> {
if let Some(ref ops) = self.i_op {
ops.create(self, name, mode)
} else {
Err(Error::ENOSYS)
}
}
/// Look up a file in this directory
pub fn lookup(&self, name: &str) -> Result<Arc<Inode>> {
if let Some(ref ops) = self.i_op {
ops.lookup(self, name)
} else {
Err(Error::ENOSYS)
}
}
/// Create a directory
pub fn mkdir(&self, name: &str, mode: u32) -> Result<Arc<Inode>> {
if let Some(ref ops) = self.i_op {
ops.mkdir(self, name, mode)
} else {
Err(Error::ENOSYS)
}
}
/// Remove a file
pub fn unlink(&self, name: &str) -> Result<()> {
if let Some(ref ops) = self.i_op {
ops.unlink(self, name)
} else {
Err(Error::ENOSYS)
}
}
/// Remove a directory
pub fn rmdir(&self, name: &str) -> Result<()> {
if let Some(ref ops) = self.i_op {
ops.rmdir(self, name)
} else {
Err(Error::ENOSYS)
}
}
}
unsafe impl Send for Inode {}
unsafe impl Sync for Inode {}
/// Inode operations trait - similar to Linux inode_operations
pub trait InodeOperations: Send + Sync + core::fmt::Debug {
/// Look up a file in directory
fn lookup(&self, dir: &Inode, name: &str) -> Result<Arc<Inode>>;
/// Create a new file
fn create(&self, dir: &Inode, name: &str, mode: u32) -> Result<Arc<Inode>>;
/// Create a directory
fn mkdir(&self, dir: &Inode, name: &str, mode: u32) -> Result<Arc<Inode>>;
/// Remove a file
fn unlink(&self, dir: &Inode, name: &str) -> Result<()>;
/// Remove a directory
fn rmdir(&self, dir: &Inode, name: &str) -> Result<()>;
/// Create a symbolic link
fn symlink(&self, dir: &Inode, name: &str, target: &str) -> Result<Arc<Inode>>;
/// Rename a file
fn rename(
&self,
old_dir: &Inode,
old_name: &str,
new_dir: &Inode,
new_name: &str,
) -> Result<()>;
/// Set attributes
fn setattr(&self, inode: &Inode, attr: &InodeAttr) -> Result<()>;
/// Get attributes
fn getattr(&self, inode: &Inode) -> Result<InodeAttr>;
/// Read symbolic link
fn readlink(&self, inode: &Inode) -> Result<String>;
/// Follow symbolic link
fn follow_link(&self, inode: &Inode) -> Result<Arc<Inode>>;
/// Truncate file
fn truncate(&self, inode: &Inode, size: u64) -> Result<()>;
/// Get extended attribute
fn getxattr(&self, inode: &Inode, name: &str) -> Result<alloc::vec::Vec<u8>>;
/// Set extended attribute
fn setxattr(&self, inode: &Inode, name: &str, value: &[u8], flags: u32) -> Result<()>;
/// List extended attributes
fn listxattr(&self, inode: &Inode) -> Result<alloc::vec::Vec<String>>;
/// Remove extended attribute
fn removexattr(&self, inode: &Inode, name: &str) -> Result<()>;
}
/// Inode attributes structure
#[derive(Debug, Clone, Copy)]
pub struct InodeAttr {
pub mode: Option<u32>,
pub uid: Option<u32>,
pub gid: Option<u32>,
pub size: Option<u64>,
pub atime: Option<TimeSpec>,
pub mtime: Option<TimeSpec>,
pub ctime: Option<TimeSpec>,
}
impl InodeAttr {
pub fn new() -> Self {
Self {
mode: None,
uid: None,
gid: None,
size: None,
atime: None,
mtime: None,
ctime: None,
}
}
pub fn with_mode(mut self, mode: u32) -> Self {
self.mode = Some(mode);
self
}
pub fn with_size(mut self, size: u64) -> Self {
self.size = Some(size);
self
}
}
/// Generic inode operations for simple filesystems
#[derive(Debug)]
pub struct GenericInodeOps;
impl InodeOperations for GenericInodeOps {
fn lookup(&self, dir: &Inode, name: &str) -> Result<Arc<Inode>> {
Err(Error::ENOENT)
}
fn create(&self, dir: &Inode, name: &str, mode: u32) -> Result<Arc<Inode>> {
Err(Error::ENOSYS)
}
fn mkdir(&self, dir: &Inode, name: &str, mode: u32) -> Result<Arc<Inode>> {
Err(Error::ENOSYS)
}
fn unlink(&self, dir: &Inode, name: &str) -> Result<()> {
Err(Error::ENOSYS)
}
fn rmdir(&self, dir: &Inode, name: &str) -> Result<()> {
Err(Error::ENOSYS)
}
fn symlink(&self, dir: &Inode, name: &str, target: &str) -> Result<Arc<Inode>> {
Err(Error::ENOSYS)
}
fn rename(
&self,
old_dir: &Inode,
old_name: &str,
new_dir: &Inode,
new_name: &str,
) -> Result<()> {
Err(Error::ENOSYS)
}
fn setattr(&self, inode: &Inode, attr: &InodeAttr) -> Result<()> {
// Apply basic attributes
if let Some(mode) = attr.mode {
inode.i_mode.store(mode, Ordering::Relaxed);
}
if let Some(uid) = attr.uid {
inode.i_uid.store(uid, Ordering::Relaxed);
}
if let Some(gid) = attr.gid {
inode.i_gid.store(gid, Ordering::Relaxed);
}
if let Some(size) = attr.size {
inode.set_size(size);
}
if let Some(atime) = attr.atime {
*inode.i_atime.lock() = atime;
}
if let Some(mtime) = attr.mtime {
*inode.i_mtime.lock() = mtime;
}
if let Some(ctime) = attr.ctime {
*inode.i_ctime.lock() = ctime;
}
Ok(())
}
fn getattr(&self, inode: &Inode) -> Result<InodeAttr> {
Ok(InodeAttr {
mode: Some(inode.i_mode.load(Ordering::Relaxed)),
uid: Some(inode.i_uid.load(Ordering::Relaxed)),
gid: Some(inode.i_gid.load(Ordering::Relaxed)),
size: Some(inode.i_size.load(Ordering::Relaxed)),
atime: Some(*inode.i_atime.lock()),
mtime: Some(*inode.i_mtime.lock()),
ctime: Some(*inode.i_ctime.lock()),
})
}
fn readlink(&self, inode: &Inode) -> Result<String> {
Err(Error::EINVAL)
}
fn follow_link(&self, inode: &Inode) -> Result<Arc<Inode>> {
Err(Error::EINVAL)
}
fn truncate(&self, inode: &Inode, size: u64) -> Result<()> {
inode.set_size(size);
Ok(())
}
fn getxattr(&self, inode: &Inode, name: &str) -> Result<alloc::vec::Vec<u8>> {
Err(Error::ENODATA)
}
fn setxattr(&self, inode: &Inode, name: &str, value: &[u8], flags: u32) -> Result<()> {
Err(Error::ENOSYS)
}
fn listxattr(&self, inode: &Inode) -> Result<alloc::vec::Vec<String>> {
Ok(alloc::vec::Vec::new())
}
fn removexattr(&self, inode: &Inode, name: &str) -> Result<()> {
Err(Error::ENODATA)
}
}

435
kernel/src/fs/mod.rs Archivo normal
Ver fichero

@@ -0,0 +1,435 @@
// SPDX-License-Identifier: GPL-2.0
//! Virtual File System (VFS) - Linux compatible
//!
//! This module provides the core filesystem abstractions and compatibility
//! with Linux VFS operations.
pub mod dentry;
pub mod devfs;
pub mod file;
pub mod inode;
pub mod mode;
pub mod mount;
pub mod operations;
pub mod path;
pub mod procfs;
pub mod ramfs;
pub mod super_block; // Add mode module
// pub mod advanced; // Advanced file system operations (removed for now)
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
pub use dentry::*;
pub use file::*;
pub use inode::*;
pub use mount::*;
pub use operations::*;
pub use path::*;
pub use super_block::*;
use crate::error::{Error, Result};
use crate::memory::{UserPtr, UserSlicePtr};
use crate::sync::{Arc, Mutex};
/// File access modes - Linux compatible
pub mod flags {
pub const O_ACCMODE: u32 = 0o00000003;
pub const O_RDONLY: u32 = 0o00000000;
pub const O_WRONLY: u32 = 0o00000001;
pub const O_RDWR: u32 = 0o00000002;
pub const O_CREAT: u32 = 0o00000100;
pub const O_EXCL: u32 = 0o00000200;
pub const O_NOCTTY: u32 = 0o00000400;
pub const O_TRUNC: u32 = 0o00001000;
pub const O_APPEND: u32 = 0o00002000;
pub const O_NONBLOCK: u32 = 0o00004000;
pub const O_DSYNC: u32 = 0o00010000;
pub const O_FASYNC: u32 = 0o00020000;
pub const O_DIRECT: u32 = 0o00040000;
pub const O_LARGEFILE: u32 = 0o00100000;
pub const O_DIRECTORY: u32 = 0o00200000;
pub const O_NOFOLLOW: u32 = 0o00400000;
pub const O_NOATIME: u32 = 0o01000000;
pub const O_CLOEXEC: u32 = 0o02000000;
pub const O_SYNC: u32 = 0o04000000 | O_DSYNC;
pub const O_PATH: u32 = 0o10000000;
pub const O_TMPFILE: u32 = 0o20000000 | O_DIRECTORY;
}
/// Seek constants
pub const SEEK_SET: i32 = 0;
pub const SEEK_CUR: i32 = 1;
pub const SEEK_END: i32 = 2;
pub const SEEK_DATA: i32 = 3;
pub const SEEK_HOLE: i32 = 4;
/// Maximum filename length
pub const NAME_MAX: usize = 255;
/// Maximum path length
pub const PATH_MAX: usize = 4096;
/// File system statistics structure
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct KStatFs {
pub f_type: u64,
pub f_bsize: u64,
pub f_blocks: u64,
pub f_bfree: u64,
pub f_bavail: u64,
pub f_files: u64,
pub f_ffree: u64,
pub f_fsid: [u32; 2],
pub f_namelen: u64,
pub f_frsize: u64,
pub f_flags: u64,
pub f_spare: [u64; 4],
}
/// File attributes structure
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct KStat {
pub st_dev: u64,
pub st_ino: u64,
pub st_nlink: u64,
pub st_mode: u32,
pub st_uid: u32,
pub st_gid: u32,
pub st_rdev: u64,
pub st_size: i64,
pub st_blksize: u64,
pub st_blocks: u64,
pub st_atime: i64,
pub st_atime_nsec: i64,
pub st_mtime: i64,
pub st_mtime_nsec: i64,
pub st_ctime: i64,
pub st_ctime_nsec: i64,
}
/// I/O vector for scatter-gather I/O
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct IoVec {
pub iov_base: *mut u8,
pub iov_len: usize,
}
/// Directory entry type returned by readdir
#[derive(Debug, Clone)]
pub struct DirEntry {
pub ino: u64,
pub off: i64,
pub reclen: u16,
pub name: String,
pub d_type: u8,
}
/// Directory entry types
pub const DT_UNKNOWN: u8 = 0;
pub const DT_FIFO: u8 = 1;
pub const DT_CHR: u8 = 2;
pub const DT_DIR: u8 = 4;
pub const DT_BLK: u8 = 6;
pub const DT_REG: u8 = 8;
pub const DT_LNK: u8 = 10;
pub const DT_SOCK: u8 = 12;
pub const DT_WHT: u8 = 14;
/// Global VFS state
static VFS: Mutex<Vfs> = Mutex::new(Vfs::new());
/// Global file descriptor table (simplified - in reality this would be
/// per-process)
static GLOBAL_FD_TABLE: Mutex<BTreeMap<i32, Arc<File>>> = Mutex::new(BTreeMap::new());
static NEXT_FD: core::sync::atomic::AtomicI32 = core::sync::atomic::AtomicI32::new(3); // Start after stdin/stdout/stderr
/// Virtual File System state
pub struct Vfs {
/// Mounted filesystems
pub mounts: Vec<Arc<VfsMount>>,
/// Root dentry
pub root: Option<Arc<Dentry>>,
/// File descriptor table (per-process will be separate)
pub fd_table: BTreeMap<i32, Arc<File>>,
/// Next file descriptor number
pub next_fd: i32,
}
impl Vfs {
const fn new() -> Self {
Self {
mounts: Vec::new(),
root: None,
fd_table: BTreeMap::new(),
next_fd: 0,
}
}
/// Mount a filesystem
pub fn mount(
&mut self,
source: &str,
target: &str,
fstype: &str,
flags: u32,
data: Option<&str>,
) -> Result<()> {
// TODO: Implement proper mount logic
// For now, just create a basic mount
let sb = Arc::new(SuperBlock::new(fstype)?);
let mount = Arc::new(VfsMount::new(sb, target, flags)?);
self.mounts.push(mount);
Ok(())
}
/// Allocate a new file descriptor
pub fn alloc_fd(&mut self) -> i32 {
let fd = self.next_fd;
self.next_fd += 1;
fd
}
/// Install a file into the file descriptor table
pub fn install_fd(&mut self, fd: i32, file: Arc<File>) {
self.fd_table.insert(fd, file);
}
/// Get a file by file descriptor
pub fn get_file(&self, fd: i32) -> Option<Arc<File>> {
self.fd_table.get(&fd).cloned()
}
/// Close a file descriptor
pub fn close_fd(&mut self, fd: i32) -> Result<()> {
self.fd_table.remove(&fd);
Ok(())
}
}
/// Initialize the VFS subsystem
pub fn init() -> Result<()> {
// Register built-in filesystems
ramfs::register_ramfs()?;
procfs::register_procfs()?;
devfs::register_devfs()?;
// Create initial mounts
mount::do_mount("none", "/", "ramfs", 0, None)?;
// Create essential directories
// TODO: Create /proc and /dev directories in root filesystem
mount::do_mount("proc", "/proc", "proc", 0, None)?;
mount::do_mount("devfs", "/dev", "devfs", 0, None)?;
crate::console::print_info("VFS: Initialized virtual file system\n");
Ok(())
}
/// Get a file descriptor from the table
pub fn get_file_descriptor(fd: i32) -> Option<Arc<File>> {
let table = GLOBAL_FD_TABLE.lock();
table.get(&fd).cloned()
}
/// Allocate a new file descriptor
pub fn allocate_file_descriptor(file: Arc<File>) -> Result<i32> {
let fd = NEXT_FD.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
let mut table = GLOBAL_FD_TABLE.lock();
table.insert(fd, file);
Ok(fd)
}
/// Close a file descriptor
pub fn close_file_descriptor(fd: i32) -> Result<()> {
let mut table = GLOBAL_FD_TABLE.lock();
table.remove(&fd).ok_or(Error::EBADF)?;
Ok(())
}
/// Open a file
pub fn open_file(path: &str, flags: i32, mode: u32) -> Result<Arc<File>> {
// For now, create a simple file structure
// In a full implementation, this would:
// 1. Parse the path
// 2. Walk the directory tree
// 3. Check permissions
// 4. Create inode/dentry structures
// 5. Return file handle
let file = File::new(path, flags as u32, mode)?;
Ok(Arc::new(file))
}
/// Read from a file
pub fn read_file(file: &Arc<File>, buf: &mut [u8]) -> Result<usize> {
if let Some(ops) = &file.f_op {
// Create a UserSlicePtr from the buffer for the interface
let user_slice = unsafe { UserSlicePtr::new(buf.as_mut_ptr(), buf.len()) };
let result = ops.read(file, user_slice, buf.len())?;
Ok(result as usize)
} else {
Err(Error::ENOSYS)
}
}
/// Write to a file
pub fn write_file(file: &Arc<File>, buf: &[u8]) -> Result<usize> {
if let Some(ops) = &file.f_op {
// Create a UserSlicePtr from the buffer for the interface
let user_slice = unsafe { UserSlicePtr::new(buf.as_ptr() as *mut u8, buf.len()) };
let result = ops.write(file, user_slice, buf.len())?;
Ok(result as usize)
} else {
Err(Error::ENOSYS)
}
}
/// Initialize VFS
pub fn init_vfs() -> Result<()> {
// Initialize filesystems - just initialize the VFS, not individual filesystems
crate::info!("VFS initialized");
Ok(())
}
/// Open a file - Linux compatible sys_open
pub fn open(pathname: &str, flags: i32, mode: u32) -> Result<i32> {
let mut vfs = VFS.lock();
// TODO: Path resolution, permission checks, etc.
// For now, create a simple file
let file = Arc::new(File::new(pathname, flags as u32, mode)?);
let fd = vfs.alloc_fd();
vfs.install_fd(fd, file);
Ok(fd)
}
/// Close a file descriptor - Linux compatible sys_close
pub fn close(fd: i32) -> Result<()> {
let mut vfs = VFS.lock();
vfs.close_fd(fd)
}
/// Read from a file descriptor - Linux compatible sys_read
pub fn read(fd: i32, buf: UserSlicePtr, count: usize) -> Result<isize> {
let vfs = VFS.lock();
let file = vfs.get_file(fd).ok_or(Error::EBADF)?;
drop(vfs);
file.read(buf, count)
}
/// Write to a file descriptor - Linux compatible sys_write
pub fn write(fd: i32, buf: UserSlicePtr, count: usize) -> Result<isize> {
let vfs = VFS.lock();
let file = vfs.get_file(fd).ok_or(Error::EBADF)?;
drop(vfs);
file.write(buf, count)
}
/// Seek within a file - Linux compatible sys_lseek
pub fn lseek(fd: i32, offset: i64, whence: i32) -> Result<i64> {
let vfs = VFS.lock();
let file = vfs.get_file(fd).ok_or(Error::EBADF)?;
drop(vfs);
file.seek(offset, whence)
}
/// Get file status - Linux compatible sys_fstat
pub fn fstat(fd: i32, statbuf: UserPtr<KStat>) -> Result<()> {
let vfs = VFS.lock();
let file = vfs.get_file(fd).ok_or(Error::EBADF)?;
drop(vfs);
let stat = file.stat()?;
statbuf.write(stat)?;
Ok(())
}
/// Generic file operations for simple filesystems
#[derive(Debug)]
pub struct GenericFileOps;
impl FileOperations for GenericFileOps {
fn read(&self, file: &File, buf: UserSlicePtr, count: usize) -> Result<isize> {
// Default read implementation
Ok(0)
}
fn write(&self, file: &File, buf: UserSlicePtr, count: usize) -> Result<isize> {
// Default write implementation
Ok(count as isize)
}
fn seek(&self, file: &File, offset: i64, whence: i32) -> Result<i64> {
// Default seek implementation
match whence {
SEEK_SET => Ok(offset),
SEEK_CUR => Ok(
file.pos.load(core::sync::atomic::Ordering::Relaxed) + offset
),
SEEK_END => Ok(offset), // TODO: Get file size
_ => Err(Error::EINVAL),
}
}
fn ioctl(&self, file: &File, cmd: u32, arg: usize) -> Result<isize> {
Err(Error::ENOTTY)
}
fn mmap(&self, file: &File, vma: &mut crate::memory::VmaArea) -> Result<()> {
Err(Error::ENODEV)
}
fn fsync(&self, file: &File, datasync: bool) -> Result<()> {
Ok(())
}
fn poll(&self, file: &File, wait: &mut PollWait) -> Result<u32> {
Ok(POLLIN | POLLOUT)
}
}
/// Poll events
pub const POLLIN: u32 = 0x001;
pub const POLLPRI: u32 = 0x002;
pub const POLLOUT: u32 = 0x004;
pub const POLLERR: u32 = 0x008;
pub const POLLHUP: u32 = 0x010;
pub const POLLNVAL: u32 = 0x020;
/// Poll wait structure (simplified)
pub struct PollWait {
// TODO: Implement proper poll/select mechanism
}
impl PollWait {
pub fn new() -> Self {
Self {}
}
}
/// Global root filesystem
static ROOT_FS: Mutex<Option<Arc<SuperBlock>>> = Mutex::new(None);
/// Initialize root filesystem
pub fn init_root_fs() -> Result<()> {
let ramfs_sb = ramfs::create_ramfs_superblock()?;
*ROOT_FS.lock() = Some(ramfs_sb);
Ok(())
}
/// Get root filesystem
pub fn get_root_fs() -> Result<Arc<SuperBlock>> {
ROOT_FS.lock().clone().ok_or(Error::NotInitialized)
}

84
kernel/src/fs/mode.rs Archivo normal
Ver fichero

@@ -0,0 +1,84 @@
// SPDX-License-Identifier: GPL-2.0
//! File mode utilities - Linux compatible
/// File mode constants (Linux compatible)
pub const S_IFMT: u32 = 0o170000; // File type mask
pub const S_IFSOCK: u32 = 0o140000; // Socket
pub const S_IFLNK: u32 = 0o120000; // Symbolic link
pub const S_IFREG: u32 = 0o100000; // Regular file
pub const S_IFBLK: u32 = 0o060000; // Block device
pub const S_IFDIR: u32 = 0o040000; // Directory
pub const S_IFCHR: u32 = 0o020000; // Character device
pub const S_IFIFO: u32 = 0o010000; // FIFO/pipe
/// Permission bits
pub const S_ISUID: u32 = 0o004000; // Set user ID
pub const S_ISGID: u32 = 0o002000; // Set group ID
pub const S_ISVTX: u32 = 0o001000; // Sticky bit
/// User permissions
pub const S_IRUSR: u32 = 0o000400; // Read by owner
pub const S_IWUSR: u32 = 0o000200; // Write by owner
pub const S_IXUSR: u32 = 0o000100; // Execute by owner
/// Group permissions
pub const S_IRGRP: u32 = 0o000040; // Read by group
pub const S_IWGRP: u32 = 0o000020; // Write by group
pub const S_IXGRP: u32 = 0o000010; // Execute by group
/// Other permissions
pub const S_IROTH: u32 = 0o000004; // Read by others
pub const S_IWOTH: u32 = 0o000002; // Write by others
pub const S_IXOTH: u32 = 0o000001; // Execute by others
/// Linux stat utility functions
pub fn s_isreg(mode: u32) -> bool {
(mode & S_IFMT) == S_IFREG
}
pub fn s_isdir(mode: u32) -> bool {
(mode & S_IFMT) == S_IFDIR
}
pub fn s_ischr(mode: u32) -> bool {
(mode & S_IFMT) == S_IFCHR
}
pub fn s_isblk(mode: u32) -> bool {
(mode & S_IFMT) == S_IFBLK
}
pub fn s_isfifo(mode: u32) -> bool {
(mode & S_IFMT) == S_IFIFO
}
pub fn s_islnk(mode: u32) -> bool {
(mode & S_IFMT) == S_IFLNK
}
pub fn s_issock(mode: u32) -> bool {
(mode & S_IFMT) == S_IFSOCK
}
/// Check if mode has execute permission for user
pub fn s_ixusr(mode: u32) -> bool {
(mode & S_IXUSR) != 0
}
/// Check if mode has execute permission for group
pub fn s_ixgrp(mode: u32) -> bool {
(mode & S_IXGRP) != 0
}
/// Check if mode has execute permission for others
pub fn s_ixoth(mode: u32) -> bool {
(mode & S_IXOTH) != 0
}
/// Default file mode (0644)
pub const DEFAULT_FILE_MODE: u32 = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
/// Default directory mode (0755)
pub const DEFAULT_DIR_MODE: u32 =
S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

309
kernel/src/fs/mount.rs Archivo normal
Ver fichero

@@ -0,0 +1,309 @@
// SPDX-License-Identifier: GPL-2.0
//! VFS mount abstraction - Linux compatible
use alloc::{format, string::String, vec::Vec}; // Add format macro
use core::sync::atomic::{AtomicU32, Ordering};
use crate::error::{Error, Result};
use crate::sync::{Arc, Mutex};
/// VFS mount structure - similar to Linux struct vfsmount
#[derive(Debug)]
pub struct VfsMount {
/// Mounted superblock
pub mnt_sb: Arc<super::SuperBlock>,
/// Mount point path
pub mnt_mountpoint: String,
/// Mount flags
pub mnt_flags: AtomicU32,
/// Parent mount
pub mnt_parent: Option<Arc<VfsMount>>,
/// Child mounts
pub mnt_children: Mutex<Vec<Arc<VfsMount>>>,
/// Reference count
pub mnt_count: AtomicU32,
/// Device name
pub mnt_devname: Option<String>,
/// Mount options
pub mnt_opts: Option<String>,
}
impl VfsMount {
/// Create a new VFS mount
pub fn new(sb: Arc<super::SuperBlock>, mountpoint: &str, flags: u32) -> Result<Self> {
Ok(Self {
mnt_sb: sb,
mnt_mountpoint: String::from(mountpoint),
mnt_flags: AtomicU32::new(flags),
mnt_parent: None,
mnt_children: Mutex::new(Vec::new()),
mnt_count: AtomicU32::new(1),
mnt_devname: None,
mnt_opts: None,
})
}
/// Set parent mount
pub fn set_parent(&mut self, parent: Arc<VfsMount>) {
self.mnt_parent = Some(parent);
}
/// Add child mount
pub fn add_child(&self, child: Arc<VfsMount>) {
let mut children = self.mnt_children.lock();
children.push(child);
}
/// Get mount flags
pub fn get_flags(&self) -> u32 {
self.mnt_flags.load(Ordering::Relaxed)
}
/// Check if mount is read-only
pub fn is_readonly(&self) -> bool {
(self.get_flags() & super::super_block::MS_RDONLY) != 0
}
/// Check if mount is nosuid
pub fn is_nosuid(&self) -> bool {
(self.get_flags() & super::super_block::MS_NOSUID) != 0
}
/// Check if mount is nodev
pub fn is_nodev(&self) -> bool {
(self.get_flags() & super::super_block::MS_NODEV) != 0
}
/// Check if mount is noexec
pub fn is_noexec(&self) -> bool {
(self.get_flags() & super::super_block::MS_NOEXEC) != 0
}
/// Increment reference count
pub fn mntget(&self) {
self.mnt_count.fetch_add(1, Ordering::Relaxed);
}
/// Decrement reference count
pub fn mntput(&self) {
let old_count = self.mnt_count.fetch_sub(1, Ordering::Relaxed);
if old_count == 1 {
// Last reference, mount should be cleaned up
// TODO: Unmount filesystem
}
}
/// Get full mount path
pub fn get_path(&self) -> String {
if let Some(ref parent) = self.mnt_parent {
if parent.mnt_mountpoint == "/" {
self.mnt_mountpoint.clone()
} else {
format!("{}{}", parent.get_path(), self.mnt_mountpoint)
}
} else {
self.mnt_mountpoint.clone()
}
}
/// Find child mount by path
pub fn find_child_mount(&self, path: &str) -> Option<Arc<VfsMount>> {
let children = self.mnt_children.lock();
for child in children.iter() {
if child.mnt_mountpoint == path {
return Some(child.clone());
}
}
None
}
}
unsafe impl Send for VfsMount {}
unsafe impl Sync for VfsMount {}
/// Mount namespace - similar to Linux struct mnt_namespace
pub struct MountNamespace {
/// Root mount
pub root: Option<Arc<VfsMount>>,
/// All mounts in this namespace
pub mounts: Mutex<Vec<Arc<VfsMount>>>,
/// Namespace ID
pub ns_id: u64,
/// Reference count
pub count: AtomicU32,
}
impl MountNamespace {
/// Create a new mount namespace
pub fn new(ns_id: u64) -> Self {
Self {
root: None,
mounts: Mutex::new(Vec::new()),
ns_id,
count: AtomicU32::new(1),
}
}
/// Add mount to namespace
pub fn add_mount(&self, mount: Arc<VfsMount>) {
let mut mounts = self.mounts.lock();
mounts.push(mount);
}
/// Remove mount from namespace
pub fn remove_mount(&self, mountpoint: &str) -> Option<Arc<VfsMount>> {
let mut mounts = self.mounts.lock();
if let Some(pos) = mounts.iter().position(|m| m.mnt_mountpoint == mountpoint) {
Some(mounts.remove(pos))
} else {
None
}
}
/// Find mount by path
pub fn find_mount(&self, path: &str) -> Option<Arc<VfsMount>> {
let mounts = self.mounts.lock();
// Find the longest matching mount point
let mut best_match: Option<Arc<VfsMount>> = None;
let mut best_len = 0;
for mount in mounts.iter() {
let mount_path = mount.get_path();
if path.starts_with(&mount_path) && mount_path.len() > best_len {
best_match = Some(mount.clone());
best_len = mount_path.len();
}
}
best_match
}
/// Get all mount points
pub fn get_mount_points(&self) -> Vec<String> {
let mounts = self.mounts.lock();
mounts.iter().map(|m| m.get_path()).collect()
}
/// Set root mount
pub fn set_root(&mut self, root: Arc<VfsMount>) {
self.root = Some(root.clone());
self.add_mount(root);
}
}
/// Global mount namespace
static INIT_MNT_NS: spin::once::Once<Mutex<MountNamespace>> = spin::once::Once::new();
fn get_init_mnt_ns() -> &'static Mutex<MountNamespace> {
INIT_MNT_NS.call_once(|| Mutex::new(MountNamespace::new(1)))
}
/// Get the init mount namespace
pub fn get_init_ns() -> &'static Mutex<MountNamespace> {
get_init_mnt_ns()
}
/// Mount a filesystem
pub fn do_mount(
dev_name: &str,
dir_name: &str,
type_name: &str,
flags: u32,
data: Option<&str>,
) -> Result<()> {
// TODO: Look up filesystem type
// For now, create a basic mount
let sb = Arc::new(super::SuperBlock::new(type_name)?);
let mount = Arc::new(VfsMount::new(sb, dir_name, flags)?);
let ns = get_init_ns();
let ns = ns.lock();
ns.add_mount(mount);
crate::console::print_info(&format!(
"Mounted {} on {} (type {})\n",
dev_name, dir_name, type_name
));
Ok(())
}
/// Unmount a filesystem
pub fn do_umount(dir_name: &str, flags: u32) -> Result<()> {
let ns = get_init_ns();
let ns = ns.lock();
if let Some(mount) = ns.remove_mount(dir_name) {
mount.mntput();
crate::console::print_info(&format!("Unmounted {}\n", dir_name));
Ok(())
} else {
Err(Error::ENOENT)
}
}
/// Get mount information for a path
pub fn path_get_mount(path: &str) -> Option<Arc<VfsMount>> {
let ns = get_init_ns();
let ns = ns.lock();
ns.find_mount(path)
}
/// Check if a path is a mount point
pub fn is_mountpoint(path: &str) -> bool {
let ns = get_init_ns();
let ns = ns.lock();
let mounts = ns.mounts.lock();
mounts.iter().any(|m| m.get_path() == path)
}
/// Get all mount points
pub fn get_all_mounts() -> Vec<String> {
let ns = get_init_ns();
let ns = ns.lock();
ns.get_mount_points()
}
/// Remount a filesystem with new flags
pub fn do_remount(dir_name: &str, flags: u32, data: Option<&str>) -> Result<()> {
let ns = get_init_ns();
let ns = ns.lock();
if let Some(mount) = ns.find_mount(dir_name) {
mount.mnt_flags.store(flags, Ordering::Relaxed);
// Also remount the superblock
if let Some(ref ops) = mount.mnt_sb.s_op {
ops.remount_fs(&mount.mnt_sb, flags, data)?;
}
crate::console::print_info(&format!(
"Remounted {} with flags {:#x}\n",
dir_name, flags
));
Ok(())
} else {
Err(Error::ENOENT)
}
}
/// Bind mount - create a bind mount
pub fn do_bind_mount(old_path: &str, new_path: &str, flags: u32) -> Result<()> {
let ns = get_init_ns();
let ns = ns.lock();
if let Some(old_mount) = ns.find_mount(old_path) {
let new_mount = Arc::new(VfsMount::new(
old_mount.mnt_sb.clone(),
new_path,
flags | super::super_block::MS_BIND,
)?);
ns.add_mount(new_mount);
crate::console::print_info(&format!("Bind mounted {} to {}\n", old_path, new_path));
Ok(())
} else {
Err(Error::ENOENT)
}
}

446
kernel/src/fs/operations.rs Archivo normal
Ver fichero

@@ -0,0 +1,446 @@
// SPDX-License-Identifier: GPL-2.0
//! Various VFS operations and utilities
use crate::error::{Error, Result};
use crate::memory::UserSlicePtr;
use crate::sync::Arc;
/// Address space operations trait - similar to Linux address_space_operations
pub trait AddressSpaceOperations: Send + Sync {
/// Write a page
fn writepage(&self, page: &crate::memory::Page) -> Result<()>;
/// Read a page
fn readpage(&self, file: Option<&super::File>, page: &crate::memory::Page) -> Result<()>;
/// Sync pages
fn sync_page(&self, page: &crate::memory::Page) -> Result<()>;
/// Write pages
fn writepages(&self, mapping: &AddressSpace, wbc: &WritebackControl) -> Result<()>;
/// Set page dirty
fn set_page_dirty(&self, page: &crate::memory::Page) -> Result<bool>;
/// Read pages ahead
fn readpages(
&self,
file: Option<&super::File>,
pages: &[&crate::memory::Page],
) -> Result<()>;
/// Write begin
fn write_begin(&self, file: &super::File, pos: u64, len: u32) -> Result<()>;
/// Write end
fn write_end(&self, file: &super::File, pos: u64, len: u32, copied: u32) -> Result<u32>;
/// Direct I/O
fn direct_io(
&self,
file: &super::File,
pos: u64,
buf: UserSlicePtr,
len: usize,
write: bool,
) -> Result<isize>;
}
/// Address space structure
pub struct AddressSpace {
/// Host inode
pub host: Option<Arc<super::Inode>>,
/// Address space operations
pub a_ops: Option<Arc<dyn AddressSpaceOperations>>,
/// Number of pages
pub nrpages: core::sync::atomic::AtomicUsize,
/// Flags
pub flags: core::sync::atomic::AtomicU32,
/// Private data
pub private_data: Option<*mut u8>,
}
impl AddressSpace {
pub fn new() -> Self {
Self {
host: None,
a_ops: None,
nrpages: core::sync::atomic::AtomicUsize::new(0),
flags: core::sync::atomic::AtomicU32::new(0),
private_data: None,
}
}
}
/// Writeback control structure
pub struct WritebackControl {
pub start: u64,
pub end: u64,
pub sync_mode: WritebackSyncMode,
pub nr_to_write: u64,
pub tagged_writepages: bool,
}
#[derive(Debug, Clone, Copy)]
pub enum WritebackSyncMode {
None,
All,
Memory,
}
/// Generic file operations implementation
#[derive(Debug)]
pub struct GenericFileOperations;
impl super::FileOperations for GenericFileOperations {
fn read(&self, file: &super::File, buf: UserSlicePtr, count: usize) -> Result<isize> {
// Generic read implementation using page cache
// TODO: Implement proper page cache read
Ok(0)
}
fn write(&self, file: &super::File, buf: UserSlicePtr, count: usize) -> Result<isize> {
// Generic write implementation using page cache
// TODO: Implement proper page cache write
Ok(count as isize)
}
fn seek(&self, file: &super::File, offset: i64, whence: i32) -> Result<i64> {
let current_pos = file.get_pos();
let new_pos = match whence {
super::SEEK_SET => offset,
super::SEEK_CUR => current_pos + offset,
super::SEEK_END => {
// Get file size from inode
if let Some(ref inode) = file.inode {
inode.get_size() as i64 + offset
} else {
offset
}
}
_ => return Err(Error::EINVAL),
};
if new_pos < 0 {
return Err(Error::EINVAL);
}
file.set_pos(new_pos);
Ok(new_pos)
}
fn ioctl(&self, file: &super::File, cmd: u32, arg: usize) -> Result<isize> {
Err(Error::ENOTTY)
}
fn mmap(&self, file: &super::File, vma: &mut crate::memory::VmaArea) -> Result<()> {
// Generic mmap implementation
// TODO: Implement proper memory mapping
Err(Error::ENODEV)
}
fn fsync(&self, file: &super::File, datasync: bool) -> Result<()> {
// Sync file data to storage
if let Some(ref inode) = file.inode {
// TODO: Sync inode and data blocks
}
Ok(())
}
fn poll(&self, file: &super::File, wait: &mut super::PollWait) -> Result<u32> {
// Regular files are always ready for I/O
Ok(super::POLLIN | super::POLLOUT)
}
fn readdir(&self, file: &super::File, ctx: &mut super::file::DirContext) -> Result<()> {
// This shouldn't be called for regular files
Err(Error::ENOTDIR)
}
}
/// Directory file operations
#[derive(Debug)]
pub struct DirectoryOperations;
impl super::FileOperations for DirectoryOperations {
fn read(&self, file: &super::File, buf: UserSlicePtr, count: usize) -> Result<isize> {
// Can't read directory as regular file
Err(Error::EISDIR)
}
fn write(&self, file: &super::File, buf: UserSlicePtr, count: usize) -> Result<isize> {
// Can't write to directory as regular file
Err(Error::EISDIR)
}
fn seek(&self, file: &super::File, offset: i64, whence: i32) -> Result<i64> {
// Directory seeking
match whence {
super::SEEK_SET => {
if offset < 0 {
return Err(Error::EINVAL);
}
file.set_pos(offset);
Ok(offset)
}
super::SEEK_CUR => {
let new_pos = file.get_pos() + offset;
if new_pos < 0 {
return Err(Error::EINVAL);
}
file.set_pos(new_pos);
Ok(new_pos)
}
super::SEEK_END => {
// Seek to end of directory
file.set_pos(i64::MAX);
Ok(i64::MAX)
}
_ => Err(Error::EINVAL),
}
}
fn ioctl(&self, file: &super::File, cmd: u32, arg: usize) -> Result<isize> {
Err(Error::ENOTTY)
}
fn mmap(&self, file: &super::File, vma: &mut crate::memory::VmaArea) -> Result<()> {
Err(Error::ENODEV)
}
fn fsync(&self, file: &super::File, datasync: bool) -> Result<()> {
// Sync directory
Ok(())
}
fn poll(&self, file: &super::File, wait: &mut super::PollWait) -> Result<u32> {
// Directories are always ready
Ok(super::POLLIN)
}
fn readdir(&self, file: &super::File, ctx: &mut super::file::DirContext) -> Result<()> {
// Read directory entries
if let Some(ref inode) = file.inode {
if let Some(ref dentry) = file.dentry {
let subdirs = dentry.d_subdirs.lock();
for (i, child) in subdirs.iter().enumerate() {
if i >= ctx.pos as usize {
let d_type = if let Some(ref child_inode) =
child.d_inode
{
let mode = child_inode.i_mode.load(core::sync::atomic::Ordering::Relaxed);
if super::mode::s_isdir(mode) {
super::DT_DIR
} else if super::mode::s_isreg(mode) {
super::DT_REG
} else if super::mode::s_islnk(mode) {
super::DT_LNK
} else if super::mode::s_ischr(mode) {
super::DT_CHR
} else if super::mode::s_isblk(mode) {
super::DT_BLK
} else if super::mode::s_isfifo(mode) {
super::DT_FIFO
} else if super::mode::s_issock(mode) {
super::DT_SOCK
} else {
super::DT_UNKNOWN
}
} else {
super::DT_UNKNOWN
};
let ino = if let Some(ref child_inode) =
child.d_inode
{
child_inode.i_ino
} else {
0
};
ctx.add_entry(ino, &child.d_name, d_type);
}
}
}
}
Ok(())
}
}
/// Special file operations (for device files)
#[derive(Debug)]
pub struct SpecialFileOperations;
impl super::FileOperations for SpecialFileOperations {
fn read(&self, file: &super::File, buf: UserSlicePtr, count: usize) -> Result<isize> {
// Delegate to device driver
if let Some(ref inode) = file.inode {
if inode.is_char_device() || inode.is_block_device() {
// TODO: Call device driver read function
return Ok(0);
}
}
Err(Error::ENODEV)
}
fn write(&self, file: &super::File, buf: UserSlicePtr, count: usize) -> Result<isize> {
// Delegate to device driver
if let Some(ref inode) = file.inode {
if inode.is_char_device() || inode.is_block_device() {
// TODO: Call device driver write function
return Ok(count as isize);
}
}
Err(Error::ENODEV)
}
fn seek(&self, file: &super::File, offset: i64, whence: i32) -> Result<i64> {
// Most device files don't support seeking
Err(Error::ESPIPE)
}
fn ioctl(&self, file: &super::File, cmd: u32, arg: usize) -> Result<isize> {
// Delegate to device driver
if let Some(ref inode) = file.inode {
if inode.is_char_device() || inode.is_block_device() {
// TODO: Call device driver ioctl function
return Ok(0);
}
}
Err(Error::ENOTTY)
}
fn mmap(&self, file: &super::File, vma: &mut crate::memory::VmaArea) -> Result<()> {
// Some device files support mmap
Err(Error::ENODEV)
}
fn fsync(&self, file: &super::File, datasync: bool) -> Result<()> {
// Nothing to sync for device files
Ok(())
}
fn poll(&self, file: &super::File, wait: &mut super::PollWait) -> Result<u32> {
// Delegate to device driver
if let Some(ref inode) = file.inode {
if inode.is_char_device() {
// TODO: Call device driver poll function
return Ok(super::POLLIN | super::POLLOUT);
}
}
Ok(0)
}
}
/// No-op address space operations
pub struct NoOpAddressSpaceOps;
impl AddressSpaceOperations for NoOpAddressSpaceOps {
fn writepage(&self, page: &crate::memory::Page) -> Result<()> {
Ok(())
}
fn readpage(&self, file: Option<&super::File>, page: &crate::memory::Page) -> Result<()> {
Ok(())
}
fn sync_page(&self, page: &crate::memory::Page) -> Result<()> {
Ok(())
}
fn writepages(&self, mapping: &AddressSpace, wbc: &WritebackControl) -> Result<()> {
Ok(())
}
fn set_page_dirty(&self, page: &crate::memory::Page) -> Result<bool> {
Ok(true)
}
fn readpages(
&self,
file: Option<&super::File>,
pages: &[&crate::memory::Page],
) -> Result<()> {
Ok(())
}
fn write_begin(&self, file: &super::File, pos: u64, len: u32) -> Result<()> {
Ok(())
}
fn write_end(&self, file: &super::File, pos: u64, len: u32, copied: u32) -> Result<u32> {
Ok(copied)
}
fn direct_io(
&self,
file: &super::File,
pos: u64,
buf: UserSlicePtr,
len: usize,
write: bool,
) -> Result<isize> {
if write {
Ok(len as isize)
} else {
Ok(0)
}
}
}
/// Helper functions for VFS operations
/// Get file operations for an inode
pub fn get_file_operations(inode: &super::Inode) -> Arc<dyn super::FileOperations> {
if let Some(ref fop) = inode.i_fop {
fop.clone()
} else {
let mode = inode.i_mode.load(core::sync::atomic::Ordering::Relaxed);
if super::mode::s_isreg(mode) {
Arc::new(GenericFileOperations)
} else if super::mode::s_isdir(mode) {
Arc::new(DirectoryOperations)
} else if super::mode::s_ischr(mode) || super::mode::s_isblk(mode) {
Arc::new(SpecialFileOperations)
} else {
Arc::new(super::GenericFileOps)
}
}
}
/// Check file permissions
pub fn check_permissions(inode: &super::Inode, mask: u32) -> Result<()> {
// TODO: Implement proper permission checking
// For now, allow all operations
Ok(())
}
/// Update access time
pub fn update_atime(inode: &super::Inode) {
inode.update_atime();
}
/// Update modification time
pub fn update_mtime(inode: &super::Inode) {
inode.update_mtime();
}
/// Truncate file to specified size
pub fn do_truncate(inode: &super::Inode, size: u64) -> Result<()> {
if let Some(ref ops) = inode.i_op {
ops.truncate(inode, size)
} else {
inode.set_size(size);
Ok(())
}
}
/// Notify directory change
pub fn notify_change(inode: &super::Inode, attr: &super::inode::InodeAttr) -> Result<()> {
if let Some(ref ops) = inode.i_op {
ops.setattr(inode, attr)
} else {
Ok(())
}
}

394
kernel/src/fs/path.rs Archivo normal
Ver fichero

@@ -0,0 +1,394 @@
// SPDX-License-Identifier: GPL-2.0
//! Path resolution and manipulation - Linux compatible
use alloc::{
format,
string::{String, ToString},
vec::Vec,
};
use crate::error::{Error, Result};
use crate::sync::Arc; // Add format macro and ToString
/// Path structure for path resolution
#[derive(Debug, Clone)]
pub struct Path {
/// Mount point
pub mnt: Option<Arc<super::VfsMount>>,
/// Dentry
pub dentry: Option<Arc<super::Dentry>>,
}
impl Path {
/// Create a new path
pub fn new() -> Self {
Self {
mnt: None,
dentry: None,
}
}
/// Create path from mount and dentry
pub fn from_mount_dentry(mnt: Arc<super::VfsMount>, dentry: Arc<super::Dentry>) -> Self {
Self {
mnt: Some(mnt),
dentry: Some(dentry),
}
}
/// Get the full path string
pub fn to_string(&self) -> String {
if let Some(ref dentry) = self.dentry {
dentry.get_path()
} else {
String::from("/")
}
}
/// Check if path is absolute
pub fn is_absolute(&self) -> bool {
self.to_string().starts_with('/')
}
/// Get parent path
pub fn parent(&self) -> Option<Path> {
if let Some(ref dentry) = self.dentry {
if let Some(ref parent) = dentry.d_parent {
Some(Path {
mnt: self.mnt.clone(),
dentry: Some(parent.clone()),
})
} else {
None
}
} else {
None
}
}
/// Get filename component
pub fn filename(&self) -> Option<String> {
if let Some(ref dentry) = self.dentry {
Some(dentry.d_name.clone())
} else {
None
}
}
/// Join with another path component
pub fn join(&self, component: &str) -> Result<Path> {
if let Some(ref dentry) = self.dentry {
if let Some(child) = dentry.find_child(component) {
Ok(Path {
mnt: self.mnt.clone(),
dentry: Some(child),
})
} else {
Err(Error::ENOENT)
}
} else {
Err(Error::ENOENT)
}
}
}
/// Path lookup flags
pub const LOOKUP_FOLLOW: u32 = 0x0001;
pub const LOOKUP_DIRECTORY: u32 = 0x0002;
pub const LOOKUP_AUTOMOUNT: u32 = 0x0004;
pub const LOOKUP_EMPTY: u32 = 0x0008;
pub const LOOKUP_OPEN: u32 = 0x0010;
pub const LOOKUP_CREATE: u32 = 0x0020;
pub const LOOKUP_EXCL: u32 = 0x0040;
pub const LOOKUP_RENAME_TARGET: u32 = 0x0080;
/// Name data structure for path resolution
pub struct NameData {
/// Path components
pub path: String,
/// Current position in path
pub pos: usize,
/// Lookup flags
pub flags: u32,
/// Root directory
pub root: Option<Path>,
/// Current working directory
pub pwd: Option<Path>,
/// Result path
pub result: Option<Path>,
/// Intent (for create/open operations)
pub intent: Option<Intent>,
}
/// Intent for path operations
#[derive(Debug, Clone)]
pub enum Intent {
Open { flags: u32, mode: u32 },
Create { mode: u32 },
Lookup,
}
impl NameData {
/// Create new name data for path resolution
pub fn new(path: String, flags: u32) -> Self {
Self {
path,
pos: 0,
flags,
root: None,
pwd: None,
result: None,
intent: None,
}
}
/// Set root directory
pub fn with_root(mut self, root: Path) -> Self {
self.root = Some(root);
self
}
/// Set current working directory
pub fn with_pwd(mut self, pwd: Path) -> Self {
self.pwd = Some(pwd);
self
}
/// Set intent
pub fn with_intent(mut self, intent: Intent) -> Self {
self.intent = Some(intent);
self
}
/// Get next path component
pub fn next_component(&mut self) -> Option<String> {
if self.pos >= self.path.len() {
return None;
}
// Skip leading slashes
while self.pos < self.path.len() && self.path.chars().nth(self.pos) == Some('/') {
self.pos += 1;
}
if self.pos >= self.path.len() {
return None;
}
// Find end of component
let start = self.pos;
while self.pos < self.path.len() && self.path.chars().nth(self.pos) != Some('/') {
self.pos += 1;
}
Some(self.path[start..self.pos].to_string())
}
/// Check if path is finished
pub fn is_finished(&self) -> bool {
self.pos >= self.path.len()
}
}
/// Resolve a path to a dentry
pub fn path_lookup(pathname: &str, flags: u32) -> Result<Path> {
let mut nd = NameData::new(String::from(pathname), flags);
// Set root directory (for now, use a dummy root)
// TODO: Get actual root from current process
// Start from root or current directory
let mut current_path = if pathname.starts_with('/') {
// Absolute path - start from root
if let Some(root) = nd.root.clone() {
root
} else {
// Create dummy root path
Path::new()
}
} else {
// Relative path - start from current directory
if let Some(pwd) = nd.pwd.clone() {
pwd
} else {
// Create dummy current directory
Path::new()
}
};
// Resolve each component
while let Some(component) = nd.next_component() {
match component.as_str() {
"." => {
// Current directory - no change
continue;
}
".." => {
// Parent directory
if let Some(parent) = current_path.parent() {
current_path = parent;
}
continue;
}
_ => {
// Regular component
current_path = current_path.join(&component)?;
}
}
// Check for mount points
if let Some(mount) = super::mount::path_get_mount(&current_path.to_string()) {
current_path.mnt = Some(mount);
}
// Handle symlinks if LOOKUP_FOLLOW is set
if (flags & LOOKUP_FOLLOW) != 0 {
if let Some(ref dentry) = current_path.dentry {
if let Some(ref inode) = dentry.d_inode {
if super::mode::s_islnk(
inode.i_mode.load(
core::sync::atomic::Ordering::Relaxed,
),
) {
// TODO: Follow symbolic link
// For now, just continue
}
}
}
}
}
nd.result = Some(current_path.clone());
Ok(current_path)
}
/// Resolve parent directory and filename
pub fn path_parent_and_name(pathname: &str) -> Result<(Path, String)> {
let path = Path::new();
// Split pathname into parent and filename
if let Some(last_slash) = pathname.rfind('/') {
let parent_path = &pathname[..last_slash];
let filename = &pathname[last_slash + 1..];
if parent_path.is_empty() {
// Root directory
Ok((path, String::from(filename)))
} else {
let parent = path_lookup(parent_path, 0)?;
Ok((parent, String::from(filename)))
}
} else {
// No slash - filename in current directory
Ok((path, String::from(pathname)))
}
}
/// Normalize a path (remove . and .. components)
pub fn normalize_path(path: &str) -> String {
let mut components = Vec::new();
for component in path.split('/') {
match component {
"" | "." => {
// Skip empty and current directory components
continue;
}
".." => {
// Parent directory - remove last component
components.pop();
}
_ => {
// Regular component
components.push(component);
}
}
}
let result = components.join("/");
if path.starts_with('/') {
format!("/{}", result)
} else {
result
}
}
/// Check if a path is safe (no .. escapes)
pub fn is_safe_path(path: &str) -> bool {
let normalized = normalize_path(path);
// Check for .. at the beginning
if normalized.starts_with("..") {
return false;
}
// Check for /../ sequences
if normalized.contains("/../") {
return false;
}
true
}
/// Join two paths
pub fn join_paths(base: &str, path: &str) -> String {
if path.starts_with('/') {
// Absolute path
String::from(path)
} else {
// Relative path
let base = base.trim_end_matches('/');
if base.is_empty() {
format!("/{}", path)
} else {
format!("{}/{}", base, path)
}
}
}
/// Get the directory part of a path
pub fn dirname(path: &str) -> &str {
if let Some(last_slash) = path.rfind('/') {
if last_slash == 0 {
"/"
} else {
&path[..last_slash]
}
} else {
"."
}
}
/// Get the filename part of a path
pub fn basename(path: &str) -> &str {
if let Some(last_slash) = path.rfind('/') {
&path[last_slash + 1..]
} else {
path
}
}
/// Get file extension
pub fn extension(path: &str) -> Option<&str> {
let filename = basename(path);
if let Some(last_dot) = filename.rfind('.') {
if last_dot > 0 {
Some(&filename[last_dot + 1..])
} else {
None
}
} else {
None
}
}
/// Check if path is absolute
pub fn is_absolute(path: &str) -> bool {
path.starts_with('/')
}
/// Check if path is relative
pub fn is_relative(path: &str) -> bool {
!is_absolute(path)
}

503
kernel/src/fs/procfs.rs Archivo normal
Ver fichero

@@ -0,0 +1,503 @@
// SPDX-License-Identifier: GPL-2.0
//! Proc filesystem implementation - Linux compatible
use alloc::{boxed::Box, collections::BTreeMap, format, string::String, vec, vec::Vec}; /* Add vec macro and Box */
use core::sync::atomic::{AtomicU64, Ordering};
use crate::error::{Error, Result};
use crate::fs::*;
use crate::memory::UserSlicePtr;
use crate::sync::{Arc, Mutex};
/// Proc filesystem entry
#[derive(Debug)]
pub struct ProcEntry {
/// Entry name
pub name: String,
/// Entry type
pub entry_type: ProcEntryType,
/// Mode
pub mode: u32,
/// Read function
pub read: Option<fn(&ProcEntry, &mut String) -> Result<()>>,
/// Write function
pub write: Option<fn(&ProcEntry, &str) -> Result<()>>,
/// Child entries (for directories)
pub children: Mutex<Vec<Arc<ProcEntry>>>,
/// Parent entry
pub parent: Option<Arc<ProcEntry>>,
/// Private data
pub private_data: Option<*mut u8>,
}
#[derive(Debug, Clone, Copy)]
pub enum ProcEntryType {
File,
Directory,
Symlink,
}
impl ProcEntry {
pub fn new_file(
name: String,
mode: u32,
read_fn: fn(&ProcEntry, &mut String) -> Result<()>,
) -> Self {
Self {
name,
entry_type: ProcEntryType::File,
mode,
read: Some(read_fn),
write: None,
children: Mutex::new(Vec::new()),
parent: None,
private_data: None,
}
}
pub fn new_dir(name: String, mode: u32) -> Self {
Self {
name,
entry_type: ProcEntryType::Directory,
mode,
read: None,
write: None,
children: Mutex::new(Vec::new()),
parent: None,
private_data: None,
}
}
pub fn add_child(self: &Arc<Self>, child: Arc<ProcEntry>) {
let mut children = self.children.lock();
children.push(child);
}
pub fn find_child(&self, name: &str) -> Option<Arc<ProcEntry>> {
let children = self.children.lock();
for child in children.iter() {
if child.name == name {
return Some(child.clone());
}
}
None
}
}
unsafe impl Send for ProcEntry {}
unsafe impl Sync for ProcEntry {}
/// Proc filesystem
pub struct ProcFs {
/// Root entry
pub root: Arc<ProcEntry>,
/// Next inode number
next_ino: AtomicU64,
/// Entry to inode mapping
entries: Mutex<BTreeMap<*const ProcEntry, u64>>,
}
impl ProcFs {
pub fn new() -> Self {
let root = Arc::new(ProcEntry::new_dir(String::from("proc"), 0o755));
let mut fs = Self {
root,
next_ino: AtomicU64::new(1),
entries: Mutex::new(BTreeMap::new()),
};
fs.create_default_entries();
fs
}
fn alloc_ino(&self) -> u64 {
self.next_ino.fetch_add(1, Ordering::Relaxed)
}
fn get_or_create_ino(&self, entry: &ProcEntry) -> u64 {
let entry_ptr = entry as *const ProcEntry;
let mut entries = self.entries.lock();
if let Some(&ino) = entries.get(&entry_ptr) {
ino
} else {
let ino = self.alloc_ino();
entries.insert(entry_ptr, ino);
ino
}
}
fn create_default_entries(&mut self) {
// Create /proc/version
let version_entry = Arc::new(ProcEntry::new_file(
String::from("version"),
0o444,
proc_version_read,
));
self.root.add_child(version_entry);
// Create /proc/meminfo
let meminfo_entry = Arc::new(ProcEntry::new_file(
String::from("meminfo"),
0o444,
proc_meminfo_read,
));
self.root.add_child(meminfo_entry);
// Create /proc/cpuinfo
let cpuinfo_entry = Arc::new(ProcEntry::new_file(
String::from("cpuinfo"),
0o444,
proc_cpuinfo_read,
));
self.root.add_child(cpuinfo_entry);
// Create /proc/uptime
let uptime_entry = Arc::new(ProcEntry::new_file(
String::from("uptime"),
0o444,
proc_uptime_read,
));
self.root.add_child(uptime_entry);
// Create /proc/loadavg
let loadavg_entry = Arc::new(ProcEntry::new_file(
String::from("loadavg"),
0o444,
proc_loadavg_read,
));
self.root.add_child(loadavg_entry);
// Create /proc/stat
let stat_entry = Arc::new(ProcEntry::new_file(
String::from("stat"),
0o444,
proc_stat_read,
));
self.root.add_child(stat_entry);
// Create /proc/mounts
let mounts_entry = Arc::new(ProcEntry::new_file(
String::from("mounts"),
0o444,
proc_mounts_read,
));
self.root.add_child(mounts_entry);
}
}
/// Proc filesystem file operations
#[derive(Debug)]
pub struct ProcFileOps {
entry: Arc<ProcEntry>,
}
impl ProcFileOps {
pub fn new(entry: Arc<ProcEntry>) -> Self {
Self { entry }
}
}
impl FileOperations for ProcFileOps {
fn read(&self, file: &File, buf: UserSlicePtr, count: usize) -> Result<isize> {
match self.entry.entry_type {
ProcEntryType::File => {
if let Some(read_fn) = self.entry.read {
let mut content = String::new();
read_fn(&self.entry, &mut content)?;
let pos = file.get_pos() as usize;
if pos >= content.len() {
return Ok(0);
}
let to_copy = core::cmp::min(count, content.len() - pos);
let data = &content.as_bytes()[pos..pos + to_copy];
buf.copy_from_slice(data)?;
file.set_pos(file.get_pos() + to_copy as i64);
Ok(to_copy as isize)
} else {
Ok(0)
}
}
_ => Err(Error::EISDIR),
}
}
fn write(&self, file: &File, buf: UserSlicePtr, count: usize) -> Result<isize> {
if let Some(write_fn) = self.entry.write {
let mut data = vec![0u8; count];
buf.copy_to_slice(&mut data)?;
let content = String::from_utf8(data).map_err(|_| Error::EINVAL)?;
write_fn(&self.entry, &content)?;
Ok(count as isize)
} else {
Err(Error::EPERM)
}
}
fn seek(&self, file: &File, offset: i64, whence: i32) -> Result<i64> {
let new_pos = match whence {
SEEK_SET => offset,
SEEK_CUR => file.get_pos() + offset,
SEEK_END => 0, // Proc files are typically small
_ => return Err(Error::EINVAL),
};
if new_pos < 0 {
return Err(Error::EINVAL);
}
file.set_pos(new_pos);
Ok(new_pos)
}
fn ioctl(&self, file: &File, cmd: u32, arg: usize) -> Result<isize> {
Err(Error::ENOTTY)
}
fn mmap(&self, file: &File, vma: &mut crate::memory::VmaArea) -> Result<()> {
Err(Error::ENODEV)
}
fn fsync(&self, file: &File, datasync: bool) -> Result<()> {
Ok(())
}
fn poll(&self, file: &File, wait: &mut PollWait) -> Result<u32> {
Ok(POLLIN | POLLOUT)
}
}
/// Proc filesystem inode operations
#[derive(Debug)]
pub struct ProcInodeOps {
fs: *const ProcFs,
}
impl ProcInodeOps {
pub fn new(fs: &ProcFs) -> Self {
Self {
fs: fs as *const ProcFs,
}
}
fn get_fs(&self) -> &ProcFs {
unsafe { &*self.fs }
}
}
unsafe impl Send for ProcInodeOps {}
unsafe impl Sync for ProcInodeOps {}
impl InodeOperations for ProcInodeOps {
fn lookup(&self, dir: &Inode, name: &str) -> Result<Arc<Inode>> {
let fs = self.get_fs();
// Find the proc entry for this inode
// This is a simplified implementation
if let Some(child) = fs.root.find_child(name) {
let ino = fs.get_or_create_ino(&child);
let mode = match child.entry_type {
ProcEntryType::File => mode::S_IFREG | child.mode,
ProcEntryType::Directory => mode::S_IFDIR | child.mode,
ProcEntryType::Symlink => mode::S_IFLNK | child.mode,
};
let mut inode = Inode::new(ino, mode);
inode.set_operations(Arc::new(ProcInodeOps::new(fs)));
inode.set_file_operations(Arc::new(ProcFileOps::new(child)));
Ok(Arc::new(inode))
} else {
Err(Error::ENOENT)
}
}
fn create(&self, dir: &Inode, name: &str, mode: u32) -> Result<Arc<Inode>> {
Err(Error::EPERM) // Proc filesystem is read-only
}
fn mkdir(&self, dir: &Inode, name: &str, mode: u32) -> Result<Arc<Inode>> {
Err(Error::EPERM)
}
fn unlink(&self, dir: &Inode, name: &str) -> Result<()> {
Err(Error::EPERM)
}
fn rmdir(&self, dir: &Inode, name: &str) -> Result<()> {
Err(Error::EPERM)
}
fn symlink(&self, dir: &Inode, name: &str, target: &str) -> Result<Arc<Inode>> {
Err(Error::EPERM)
}
fn rename(
&self,
old_dir: &Inode,
old_name: &str,
new_dir: &Inode,
new_name: &str,
) -> Result<()> {
Err(Error::EPERM)
}
fn setattr(&self, inode: &Inode, attr: &InodeAttr) -> Result<()> {
Err(Error::EPERM)
}
fn getattr(&self, inode: &Inode) -> Result<InodeAttr> {
let generic_ops = GenericInodeOps;
generic_ops.getattr(inode)
}
fn readlink(&self, inode: &Inode) -> Result<String> {
Err(Error::EINVAL)
}
fn follow_link(&self, inode: &Inode) -> Result<Arc<Inode>> {
Err(Error::EINVAL)
}
fn truncate(&self, inode: &Inode, size: u64) -> Result<()> {
Err(Error::EPERM)
}
fn getxattr(&self, inode: &Inode, name: &str) -> Result<Vec<u8>> {
Err(Error::ENODATA)
}
fn setxattr(&self, inode: &Inode, name: &str, value: &[u8], flags: u32) -> Result<()> {
Err(Error::EPERM)
}
fn listxattr(&self, inode: &Inode) -> Result<Vec<String>> {
Ok(Vec::new())
}
fn removexattr(&self, inode: &Inode, name: &str) -> Result<()> {
Err(Error::EPERM)
}
}
// Proc file read functions
fn proc_version_read(_entry: &ProcEntry, content: &mut String) -> Result<()> {
content.push_str(&format!(
"{} version {} ({})\n",
crate::NAME,
crate::VERSION,
"rustc"
));
Ok(())
}
fn proc_meminfo_read(_entry: &ProcEntry, content: &mut String) -> Result<()> {
// TODO: Get actual memory statistics
let total_mem = 128 * 1024; // 128 MB placeholder
let free_mem = 64 * 1024; // 64 MB placeholder
content.push_str(&format!(
"MemTotal: {} kB\n\
MemFree: {} kB\n\
MemAvailable: {} kB\n\
Buffers: {} kB\n\
Cached: {} kB\n",
total_mem, free_mem, free_mem, 0, 0
));
Ok(())
}
fn proc_cpuinfo_read(_entry: &ProcEntry, content: &mut String) -> Result<()> {
// TODO: Get actual CPU information
content.push_str(
"processor\t: 0\n\
vendor_id\t: RustKernel\n\
cpu family\t: 1\n\
model\t\t: 1\n\
model name\t: Rust Kernel CPU\n\
stepping\t: 1\n\
microcode\t: 0x1\n\
cpu MHz\t\t: 1000.000\n\
cache size\t: 1024 KB\n\
flags\t\t: rust\n\n",
);
Ok(())
}
fn proc_uptime_read(_entry: &ProcEntry, content: &mut String) -> Result<()> {
// TODO: Get actual uptime
let uptime = 100.0; // 100 seconds placeholder
let idle = 90.0; // 90 seconds idle placeholder
content.push_str(&format!("{:.2} {:.2}\n", uptime, idle));
Ok(())
}
fn proc_loadavg_read(_entry: &ProcEntry, content: &mut String) -> Result<()> {
// TODO: Get actual load average
content.push_str("0.00 0.00 0.00 1/1 1\n");
Ok(())
}
fn proc_stat_read(_entry: &ProcEntry, content: &mut String) -> Result<()> {
// TODO: Get actual system statistics
content.push_str(
"cpu 0 0 0 1000 0 0 0 0 0 0\n\
cpu0 0 0 0 1000 0 0 0 0 0 0\n\
intr 0\n\
ctxt 0\n\
btime 0\n\
processes 1\n\
procs_running 1\n\
procs_blocked 0\n",
);
Ok(())
}
fn proc_mounts_read(_entry: &ProcEntry, content: &mut String) -> Result<()> {
// TODO: Get actual mount information
let mounts = crate::fs::mount::get_all_mounts();
for mount in mounts {
content.push_str(&format!("none {} ramfs rw 0 0\n", mount));
}
Ok(())
}
/// Mount proc filesystem
pub fn mount_procfs(_dev_name: &str, _flags: u32, _data: Option<&str>) -> Result<Arc<SuperBlock>> {
let mut sb = SuperBlock::new("proc")?;
sb.s_magic = 0x9fa0; // PROC_SUPER_MAGIC
let procfs = Box::leak(Box::new(ProcFs::new()));
sb.s_fs_info = Some(procfs as *mut ProcFs as *mut u8);
// Create root inode
let root_inode = Arc::new({
let mut inode = Inode::new(1, mode::S_IFDIR | 0o755);
inode.set_operations(Arc::new(ProcInodeOps::new(procfs)));
inode
});
let root_dentry = Arc::new(Dentry::new(String::from("/"), Some(root_inode)));
sb.s_root = Some(root_dentry);
Ok(Arc::new(sb))
}
/// Register proc filesystem
pub fn register_procfs() -> Result<()> {
let procfs_type = FileSystemType::new(
String::from("proc"),
|_fstype, flags, _dev_name, data| mount_procfs(_dev_name, flags, data),
|_sb| Ok(()),
);
// TODO: Register with VFS
crate::console::print_info("Registered proc filesystem\n");
Ok(())
}

406
kernel/src/fs/ramfs.rs Archivo normal
Ver fichero

@@ -0,0 +1,406 @@
// SPDX-License-Identifier: GPL-2.0
//! Simple RAM filesystem implementation
use alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec}; // Add Box import
use core::sync::atomic::{AtomicU64, Ordering};
use crate::error::{Error, Result};
use crate::fs::inode::GenericInodeOps;
use crate::fs::*;
use crate::sync::{Arc, Mutex};
const NAME_MAX: usize = 255;
/// RAM filesystem superblock
pub struct RamFs {
/// Next inode number
next_ino: AtomicU64,
/// Inode storage
inodes: Mutex<BTreeMap<u64, Arc<Inode>>>,
/// Directory entries
entries: Mutex<BTreeMap<u64, Vec<Arc<Dentry>>>>,
}
impl RamFs {
pub fn new() -> Self {
Self {
next_ino: AtomicU64::new(1),
inodes: Mutex::new(BTreeMap::new()),
entries: Mutex::new(BTreeMap::new()),
}
}
fn alloc_ino(&self) -> u64 {
self.next_ino.fetch_add(1, Ordering::Relaxed)
}
fn create_inode(&self, mode: u32) -> Arc<Inode> {
let ino = self.alloc_ino();
let mut inode = Inode::new(ino, mode);
inode.set_operations(Arc::new(RamFsInodeOps::new(self)));
let inode = Arc::new(inode);
let mut inodes = self.inodes.lock();
inodes.insert(ino, inode.clone());
if mode::s_isdir(mode) {
let mut entries = self.entries.lock();
entries.insert(ino, Vec::new());
}
inode
}
fn get_inode(&self, ino: u64) -> Option<Arc<Inode>> {
let inodes = self.inodes.lock();
inodes.get(&ino).cloned()
}
fn add_entry(&self, dir_ino: u64, name: String, child_ino: u64) -> Result<()> {
let child_inode = self.get_inode(child_ino).ok_or(Error::ENOENT)?;
let dentry = Arc::new(Dentry::new(name, Some(child_inode)));
let mut entries = self.entries.lock();
if let Some(dir_entries) = entries.get_mut(&dir_ino) {
dir_entries.push(dentry);
Ok(())
} else {
Err(Error::ENOTDIR)
}
}
fn find_entry(&self, dir_ino: u64, name: &str) -> Option<Arc<Dentry>> {
let entries = self.entries.lock();
if let Some(dir_entries) = entries.get(&dir_ino) {
for entry in dir_entries {
if entry.d_name == name {
return Some(entry.clone());
}
}
}
None
}
fn remove_entry(&self, dir_ino: u64, name: &str) -> Result<()> {
let mut entries = self.entries.lock();
if let Some(dir_entries) = entries.get_mut(&dir_ino) {
if let Some(pos) = dir_entries.iter().position(|e| e.d_name == name) {
dir_entries.remove(pos);
Ok(())
} else {
Err(Error::ENOENT)
}
} else {
Err(Error::ENOTDIR)
}
}
}
/// RAM filesystem inode operations
#[derive(Debug)]
pub struct RamFsInodeOps {
fs: *const RamFs,
}
impl RamFsInodeOps {
fn new(fs: &RamFs) -> Self {
Self {
fs: fs as *const RamFs,
}
}
fn get_fs(&self) -> &RamFs {
unsafe { &*self.fs }
}
}
unsafe impl Send for RamFsInodeOps {}
unsafe impl Sync for RamFsInodeOps {}
impl InodeOperations for RamFsInodeOps {
fn lookup(&self, dir: &Inode, name: &str) -> Result<Arc<Inode>> {
let fs = self.get_fs();
if let Some(entry) = fs.find_entry(dir.i_ino, name) {
if let Some(inode) = &entry.d_inode {
Ok(Arc::clone(inode))
} else {
Err(Error::ENOENT)
}
} else {
Err(Error::ENOENT)
}
}
fn create(&self, dir: &Inode, name: &str, mode: u32) -> Result<Arc<Inode>> {
let fs = self.get_fs();
// Check if entry already exists
if fs.find_entry(dir.i_ino, name).is_some() {
return Err(Error::EEXIST);
}
let inode = fs.create_inode(mode | mode::S_IFREG);
fs.add_entry(dir.i_ino, String::from(name), inode.i_ino)?;
Ok(inode)
}
fn mkdir(&self, dir: &Inode, name: &str, mode: u32) -> Result<Arc<Inode>> {
let fs = self.get_fs();
// Check if entry already exists
if fs.find_entry(dir.i_ino, name).is_some() {
return Err(Error::EEXIST);
}
let inode = fs.create_inode(mode | mode::S_IFDIR);
fs.add_entry(dir.i_ino, String::from(name), inode.i_ino)?;
// Add . and .. entries
fs.add_entry(inode.i_ino, String::from("."), inode.i_ino)?;
fs.add_entry(inode.i_ino, String::from(".."), dir.i_ino)?;
Ok(inode)
}
fn unlink(&self, dir: &Inode, name: &str) -> Result<()> {
let fs = self.get_fs();
fs.remove_entry(dir.i_ino, name)
}
fn rmdir(&self, dir: &Inode, name: &str) -> Result<()> {
let fs = self.get_fs();
// Check if directory is empty (only . and .. entries)
let entries = fs.entries.lock();
if let Some(target_inode) = fs
.find_entry(dir.i_ino, name)
.and_then(|e| e.d_inode.clone())
{
if let Some(dir_entries) = entries.get(&target_inode.i_ino) {
if dir_entries.len() > 2 {
return Err(Error::ENOTEMPTY);
}
}
}
drop(entries);
fs.remove_entry(dir.i_ino, name)
}
fn symlink(&self, dir: &Inode, name: &str, target: &str) -> Result<Arc<Inode>> {
let fs = self.get_fs();
// Check if entry already exists
if fs.find_entry(dir.i_ino, name).is_some() {
return Err(Error::EEXIST);
}
let inode = fs.create_inode(mode::S_IFLNK | 0o777);
// TODO: Store symlink target
fs.add_entry(dir.i_ino, String::from(name), inode.i_ino)?;
Ok(inode)
}
fn rename(
&self,
old_dir: &Inode,
old_name: &str,
new_dir: &Inode,
new_name: &str,
) -> Result<()> {
let fs = self.get_fs();
// Find the entry to rename
if let Some(entry) = fs.find_entry(old_dir.i_ino, old_name) {
// Remove from old location
fs.remove_entry(old_dir.i_ino, old_name)?;
// Add to new location
if let Some(inode) = &entry.d_inode {
fs.add_entry(new_dir.i_ino, String::from(new_name), inode.i_ino)?;
}
Ok(())
} else {
Err(Error::ENOENT)
}
}
fn setattr(&self, inode: &Inode, attr: &InodeAttr) -> Result<()> {
// Apply basic attributes using generic implementation
let generic_ops = GenericInodeOps;
generic_ops.setattr(inode, attr)
}
fn getattr(&self, inode: &Inode) -> Result<InodeAttr> {
let generic_ops = GenericInodeOps;
generic_ops.getattr(inode)
}
fn readlink(&self, inode: &Inode) -> Result<String> {
// TODO: Return stored symlink target
Err(Error::EINVAL)
}
fn follow_link(&self, inode: &Inode) -> Result<Arc<Inode>> {
// TODO: Follow symlink to target
Err(Error::EINVAL)
}
fn truncate(&self, inode: &Inode, size: u64) -> Result<()> {
inode.set_size(size);
Ok(())
}
fn getxattr(&self, inode: &Inode, name: &str) -> Result<Vec<u8>> {
Err(Error::ENODATA)
}
fn setxattr(&self, inode: &Inode, name: &str, value: &[u8], flags: u32) -> Result<()> {
Err(Error::ENOSYS)
}
fn listxattr(&self, inode: &Inode) -> Result<Vec<String>> {
Ok(Vec::new())
}
fn removexattr(&self, inode: &Inode, name: &str) -> Result<()> {
Err(Error::ENODATA)
}
}
/// Mount RAM filesystem
pub fn mount_ramfs(_dev_name: &str, _flags: u32, _data: Option<&str>) -> Result<Arc<SuperBlock>> {
let mut sb = SuperBlock::new("ramfs")?;
sb.s_magic = 0x858458f6; // RAMFS magic
sb.set_operations(Arc::new(RamFsSuperOps));
let ramfs = Box::leak(Box::new(RamFs::new()));
sb.s_fs_info = Some(ramfs as *mut RamFs as *mut u8);
// Create root directory
let root_inode = ramfs.create_inode(mode::S_IFDIR | 0o755);
let root_dentry = Arc::new(Dentry::new(String::from("/"), Some(root_inode)));
let sb = Arc::new(sb);
Ok(sb)
}
/// RAM filesystem superblock operations
#[derive(Debug)]
pub struct RamFsSuperOps;
impl SuperOperations for RamFsSuperOps {
fn alloc_inode(&self, sb: &SuperBlock) -> Result<Arc<Inode>> {
let ramfs = unsafe { &*(sb.s_fs_info.unwrap() as *const RamFs) };
Ok(ramfs.create_inode(0o644))
}
fn destroy_inode(&self, inode: &Inode) -> Result<()> {
Ok(())
}
fn write_inode(&self, inode: &Inode, sync: bool) -> Result<()> {
// RAM filesystem doesn't need to write inodes
Ok(())
}
fn delete_inode(&self, inode: &Inode) -> Result<()> {
Ok(())
}
fn put_super(&self, sb: &SuperBlock) -> Result<()> {
if let Some(fs_info) = sb.s_fs_info {
unsafe {
let ramfs = Box::from_raw(fs_info as *mut RamFs);
drop(ramfs);
}
}
Ok(())
}
fn write_super(&self, sb: &SuperBlock) -> Result<()> {
// Nothing to write for RAM filesystem
Ok(())
}
fn sync_fs(&self, sb: &SuperBlock, wait: bool) -> Result<()> {
// Nothing to sync for RAM filesystem
Ok(())
}
fn freeze_fs(&self, sb: &SuperBlock) -> Result<()> {
Ok(())
}
fn unfreeze_fs(&self, sb: &SuperBlock) -> Result<()> {
Ok(())
}
fn statfs(&self, sb: &SuperBlock) -> Result<KStatFs> {
Ok(KStatFs {
f_type: sb.s_magic as u64,
f_bsize: sb.s_blocksize as u64,
f_blocks: 0, // Unlimited
f_bfree: 0, // Unlimited
f_bavail: 0, // Unlimited
f_files: 0, // Dynamic
f_ffree: 0, // Unlimited
f_fsid: [0, 0],
f_namelen: NAME_MAX as u64,
f_frsize: sb.s_blocksize as u64,
f_flags: 0,
f_spare: [0; 4],
})
}
fn remount_fs(&self, sb: &SuperBlock, flags: u32, data: Option<&str>) -> Result<()> {
sb.s_flags.store(flags, Ordering::Relaxed);
Ok(())
}
fn show_options(&self, sb: &SuperBlock) -> Result<String> {
Ok(String::new())
}
}
/// Kill RAM filesystem superblock
pub fn kill_ramfs(sb: &SuperBlock) -> Result<()> {
if let Some(ref ops) = sb.s_op {
ops.put_super(sb)
} else {
Ok(())
}
}
/// Create a RAM filesystem superblock
pub fn create_ramfs_superblock() -> Result<Arc<SuperBlock>> {
let mut sb = SuperBlock::new("ramfs")?;
sb.s_magic = 0x858458f6; // RAMFS magic
sb.set_operations(Arc::new(RamFsSuperOps));
let ramfs = Box::leak(Box::new(RamFs::new()));
sb.s_fs_info = Some(ramfs as *mut RamFs as *mut u8);
// Create root directory
let root_inode = ramfs.create_inode(mode::S_IFDIR | 0o755);
Ok(Arc::new(sb))
}
/// Register RAM filesystem
pub fn register_ramfs() -> Result<()> {
let ramfs_type = FileSystemType::new(
String::from("ramfs"),
|_fstype, flags, _dev_name, data| mount_ramfs(_dev_name, flags, data),
|sb| kill_ramfs(sb),
);
// TODO: Register with VFS
crate::console::print_info("Registered ramfs filesystem\n");
Ok(())
}

363
kernel/src/fs/super_block.rs Archivo normal
Ver fichero

@@ -0,0 +1,363 @@
// SPDX-License-Identifier: GPL-2.0
//! Superblock abstraction - Linux compatible
use alloc::string::String;
use alloc::vec::Vec;
use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};
use crate::device::DeviceNumber;
use crate::error::Result;
use crate::sync::{Arc, Mutex};
/// Superblock structure - similar to Linux struct super_block
#[derive(Debug)]
pub struct SuperBlock {
/// Device number
pub s_dev: DeviceNumber,
/// Block size
pub s_blocksize: u32,
/// Block size bits
pub s_blocksize_bits: u8,
/// Maximum file size
pub s_maxbytes: u64,
/// File system type
pub s_type: Option<Arc<FileSystemType>>,
/// Superblock operations
pub s_op: Option<Arc<dyn SuperOperations>>,
/// Root dentry
pub s_root: Option<Arc<super::Dentry>>,
/// Mount point
pub s_mount: Option<Arc<super::VfsMount>>,
/// File system flags
pub s_flags: AtomicU32,
/// File system magic number
pub s_magic: u32,
/// List of inodes
pub s_inodes: Mutex<Vec<Arc<super::Inode>>>,
/// Next inode number
pub s_next_ino: AtomicU64,
/// Private data
pub s_fs_info: Option<*mut u8>,
/// Dirty inodes
pub s_dirty: Mutex<Vec<Arc<super::Inode>>>,
/// Reference count
pub s_count: AtomicU32,
/// File system name
pub s_id: String,
}
impl SuperBlock {
/// Create a new superblock
pub fn new(fstype: &str) -> Result<Self> {
Ok(Self {
s_dev: DeviceNumber::new(0, 0),
s_blocksize: 4096,
s_blocksize_bits: 12,
s_maxbytes: 0x7fffffffffffffff,
s_type: None,
s_op: None,
s_root: None,
s_mount: None,
s_flags: AtomicU32::new(0),
s_magic: 0,
s_inodes: Mutex::new(Vec::new()),
s_next_ino: AtomicU64::new(1),
s_fs_info: None,
s_dirty: Mutex::new(Vec::new()),
s_count: AtomicU32::new(1),
s_id: String::from(fstype),
})
}
/// Set superblock operations
pub fn set_operations(&mut self, ops: Arc<dyn SuperOperations>) {
self.s_op = Some(ops);
}
/// Allocate a new inode
pub fn alloc_inode(&self, mode: u32) -> Result<Arc<super::Inode>> {
let ino = self.s_next_ino.fetch_add(1, Ordering::Relaxed);
let mut inode = super::Inode::new(ino, mode);
inode.i_sb = Some(Arc::new(unsafe {
// SAFETY: We're creating a weak reference to avoid cycles
core::ptr::read(self as *const Self)
}));
let inode = Arc::new(inode);
// Add to inode list
let mut inodes = self.s_inodes.lock();
inodes.push(inode.clone());
Ok(inode)
}
/// Write superblock to disk
pub fn write_super(&self) -> Result<()> {
if let Some(ref ops) = self.s_op {
ops.write_super(self)
} else {
Ok(())
}
}
/// Put superblock (decrement reference count)
pub fn put_super(&self) -> Result<()> {
let old_count = self.s_count.fetch_sub(1, Ordering::Relaxed);
if old_count == 1 {
// Last reference, cleanup
if let Some(ref ops) = self.s_op {
ops.put_super(self)?;
}
}
Ok(())
}
/// Get superblock statistics
pub fn statfs(&self) -> Result<super::KStatFs> {
if let Some(ref ops) = self.s_op {
ops.statfs(self)
} else {
// Default statistics
Ok(super::KStatFs {
f_type: self.s_magic as u64,
f_bsize: self.s_blocksize as u64,
f_blocks: 0,
f_bfree: 0,
f_bavail: 0,
f_files: 0,
f_ffree: 0,
f_fsid: [0, 0],
f_namelen: super::NAME_MAX as u64,
f_frsize: self.s_blocksize as u64,
f_flags: self.s_flags.load(Ordering::Relaxed) as u64,
f_spare: [0; 4],
})
}
}
/// Sync filesystem
pub fn sync_fs(&self, wait: bool) -> Result<()> {
if let Some(ref ops) = self.s_op {
ops.sync_fs(self, wait)
} else {
Ok(())
}
}
/// Freeze filesystem
pub fn freeze_fs(&self) -> Result<()> {
if let Some(ref ops) = self.s_op {
ops.freeze_fs(self)
} else {
Ok(())
}
}
/// Unfreeze filesystem
pub fn unfreeze_fs(&self) -> Result<()> {
if let Some(ref ops) = self.s_op {
ops.unfreeze_fs(self)
} else {
Ok(())
}
}
/// Mark inode as dirty
pub fn mark_dirty(&self, inode: Arc<super::Inode>) {
let mut dirty = self.s_dirty.lock();
dirty.push(inode);
}
/// Write back dirty inodes
pub fn write_dirty(&self) -> Result<()> {
let mut dirty = self.s_dirty.lock();
for inode in dirty.drain(..) {
// TODO: Write inode to disk
}
Ok(())
}
}
unsafe impl Send for SuperBlock {}
unsafe impl Sync for SuperBlock {}
/// Superblock operations trait - similar to Linux super_operations
pub trait SuperOperations: Send + Sync + core::fmt::Debug {
/// Allocate inode
fn alloc_inode(&self, sb: &SuperBlock) -> Result<Arc<super::Inode>>;
/// Destroy inode
fn destroy_inode(&self, inode: &super::Inode) -> Result<()>;
/// Write inode
fn write_inode(&self, inode: &super::Inode, sync: bool) -> Result<()>;
/// Delete inode
fn delete_inode(&self, inode: &super::Inode) -> Result<()>;
/// Put superblock
fn put_super(&self, sb: &SuperBlock) -> Result<()>;
/// Write superblock
fn write_super(&self, sb: &SuperBlock) -> Result<()>;
/// Sync filesystem
fn sync_fs(&self, sb: &SuperBlock, wait: bool) -> Result<()>;
/// Freeze filesystem
fn freeze_fs(&self, sb: &SuperBlock) -> Result<()>;
/// Unfreeze filesystem
fn unfreeze_fs(&self, sb: &SuperBlock) -> Result<()>;
/// Get filesystem statistics
fn statfs(&self, sb: &SuperBlock) -> Result<super::KStatFs>;
/// Remount filesystem
fn remount_fs(&self, sb: &SuperBlock, flags: u32, data: Option<&str>) -> Result<()>;
/// Show mount options
fn show_options(&self, sb: &SuperBlock) -> Result<String>;
}
/// File system type structure - similar to Linux file_system_type
#[derive(Debug)]
pub struct FileSystemType {
/// File system name
pub name: String,
/// File system flags
pub fs_flags: u32,
/// Mount function
pub mount: fn(
fstype: &FileSystemType,
flags: u32,
dev_name: &str,
data: Option<&str>,
) -> Result<Arc<SuperBlock>>,
/// Kill superblock function
pub kill_sb: fn(sb: &SuperBlock) -> Result<()>,
/// Owner module
pub owner: Option<&'static str>,
}
impl FileSystemType {
/// Create a new file system type
pub fn new(
name: String,
mount: fn(&FileSystemType, u32, &str, Option<&str>) -> Result<Arc<SuperBlock>>,
kill_sb: fn(&SuperBlock) -> Result<()>,
) -> Self {
Self {
name,
fs_flags: 0,
mount,
kill_sb,
owner: None,
}
}
/// Mount this filesystem type
pub fn do_mount(
&self,
flags: u32,
dev_name: &str,
data: Option<&str>,
) -> Result<Arc<SuperBlock>> {
(self.mount)(self, flags, dev_name, data)
}
/// Kill superblock
pub fn do_kill_sb(&self, sb: &SuperBlock) -> Result<()> {
(self.kill_sb)(sb)
}
}
/// Generic superblock operations
#[derive(Debug)]
pub struct GenericSuperOps;
impl SuperOperations for GenericSuperOps {
fn alloc_inode(&self, sb: &SuperBlock) -> Result<Arc<super::Inode>> {
sb.alloc_inode(0o644)
}
fn destroy_inode(&self, inode: &super::Inode) -> Result<()> {
Ok(())
}
fn write_inode(&self, inode: &super::Inode, sync: bool) -> Result<()> {
Ok(())
}
fn delete_inode(&self, inode: &super::Inode) -> Result<()> {
Ok(())
}
fn put_super(&self, sb: &SuperBlock) -> Result<()> {
Ok(())
}
fn write_super(&self, sb: &SuperBlock) -> Result<()> {
Ok(())
}
fn sync_fs(&self, sb: &SuperBlock, wait: bool) -> Result<()> {
sb.write_dirty()
}
fn freeze_fs(&self, sb: &SuperBlock) -> Result<()> {
Ok(())
}
fn unfreeze_fs(&self, sb: &SuperBlock) -> Result<()> {
Ok(())
}
fn statfs(&self, sb: &SuperBlock) -> Result<super::KStatFs> {
sb.statfs()
}
fn remount_fs(&self, sb: &SuperBlock, flags: u32, data: Option<&str>) -> Result<()> {
sb.s_flags.store(flags, Ordering::Relaxed);
Ok(())
}
fn show_options(&self, sb: &SuperBlock) -> Result<String> {
Ok(String::new())
}
}
/// File system flags
pub const FS_REQUIRES_DEV: u32 = 1;
pub const FS_BINARY_MOUNTDATA: u32 = 2;
pub const FS_HAS_SUBTYPE: u32 = 4;
pub const FS_USERNS_MOUNT: u32 = 8;
pub const FS_DISALLOW_NOTIFY_PERM: u32 = 16;
pub const FS_RENAME_DOES_D_MOVE: u32 = 32;
/// Mount flags
pub const MS_RDONLY: u32 = 1;
pub const MS_NOSUID: u32 = 2;
pub const MS_NODEV: u32 = 4;
pub const MS_NOEXEC: u32 = 8;
pub const MS_SYNCHRONOUS: u32 = 16;
pub const MS_REMOUNT: u32 = 32;
pub const MS_MANDLOCK: u32 = 64;
pub const MS_DIRSYNC: u32 = 128;
pub const MS_NOATIME: u32 = 1024;
pub const MS_NODIRATIME: u32 = 2048;
pub const MS_BIND: u32 = 4096;
pub const MS_MOVE: u32 = 8192;
pub const MS_REC: u32 = 16384;
pub const MS_SILENT: u32 = 32768;
pub const MS_POSIXACL: u32 = 1 << 16;
pub const MS_UNBINDABLE: u32 = 1 << 17;
pub const MS_PRIVATE: u32 = 1 << 18;
pub const MS_SLAVE: u32 = 1 << 19;
pub const MS_SHARED: u32 = 1 << 20;
pub const MS_RELATIME: u32 = 1 << 21;
pub const MS_KERNMOUNT: u32 = 1 << 22;
pub const MS_I_VERSION: u32 = 1 << 23;
pub const MS_STRICTATIME: u32 = 1 << 24;

278
kernel/src/hardware.rs Archivo normal
Ver fichero

@@ -0,0 +1,278 @@
// SPDX-License-Identifier: GPL-2.0
//! Hardware detection and initialization
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use crate::driver::{PciBar, PciDevice};
use crate::error::Result;
/// CPU Information
#[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: u32,
pub core_count: u32,
pub thread_count: u32,
}
/// System Information
#[derive(Debug, Clone)]
pub struct SystemInfo {
pub cpu: CpuInfo,
pub total_memory: usize,
pub available_memory: usize,
pub boot_device: String,
pub acpi_available: bool,
pub pci_devices: Vec<PciDevice>,
}
/// Initialize hardware detection
pub fn init() -> Result<()> {
crate::info!("Initializing hardware detection...");
// Detect CPU
let cpu_info = detect_cpu()?;
crate::info!("CPU: {} {}", cpu_info.vendor, cpu_info.model_name);
crate::info!("CPU Cores: {}", cpu_info.core_count);
// Detect memory
let memory_info = detect_memory()?;
crate::info!("Total Memory: {} MB", memory_info / (1024 * 1024));
// Detect PCI devices
let pci_devices = detect_pci_devices()?;
crate::info!("Found {} PCI devices", pci_devices.len());
Ok(())
}
/// Detect CPU information
pub fn detect_cpu() -> Result<CpuInfo> {
let mut cpu_info = CpuInfo {
vendor: String::new(),
model_name: String::new(),
family: 0,
model: 0,
stepping: 0,
features: Vec::new(),
cache_size: 0,
core_count: 1,
thread_count: 1,
};
// Get CPU vendor
let (_, vendor_ebx, vendor_ecx, vendor_edx) = cpuid(0);
cpu_info.vendor = format!(
"{}{}{}",
u32_to_string(vendor_ebx),
u32_to_string(vendor_edx),
u32_to_string(vendor_ecx)
);
// Get CPU features and family/model
let (version_eax, _ebx, feature_ecx, feature_edx) = cpuid(1);
cpu_info.family = (version_eax >> 8) & 0xF;
cpu_info.model = (version_eax >> 4) & 0xF;
cpu_info.stepping = version_eax & 0xF;
// Extended family/model for newer CPUs
if cpu_info.family == 0xF {
cpu_info.family += (version_eax >> 20) & 0xFF;
}
if cpu_info.family == 0x6 || cpu_info.family == 0xF {
cpu_info.model += ((version_eax >> 16) & 0xF) << 4;
}
// Check for common features
if feature_edx & (1 << 23) != 0 {
cpu_info.features.push("MMX".to_string());
}
if feature_edx & (1 << 25) != 0 {
cpu_info.features.push("SSE".to_string());
}
if feature_edx & (1 << 26) != 0 {
cpu_info.features.push("SSE2".to_string());
}
if feature_ecx & (1 << 0) != 0 {
cpu_info.features.push("SSE3".to_string());
}
if feature_ecx & (1 << 9) != 0 {
cpu_info.features.push("SSSE3".to_string());
}
if feature_ecx & (1 << 19) != 0 {
cpu_info.features.push("SSE4.1".to_string());
}
if feature_ecx & (1 << 20) != 0 {
cpu_info.features.push("SSE4.2".to_string());
}
// Get model name from extended CPUID
let max_extended = cpuid(0x80000000).0;
if max_extended >= 0x80000004 {
let mut model_name = String::new();
for i in 0x80000002..=0x80000004 {
let (eax, ebx, ecx, edx) = cpuid(i);
model_name.push_str(&u32_to_string(eax));
model_name.push_str(&u32_to_string(ebx));
model_name.push_str(&u32_to_string(ecx));
model_name.push_str(&u32_to_string(edx));
}
cpu_info.model_name = model_name.trim().to_string();
}
Ok(cpu_info)
}
/// Detect system memory
pub fn detect_memory() -> Result<usize> {
// Use multiple methods to detect memory
// Method 1: CMOS
let cmos_memory = unsafe {
crate::arch::x86_64::port::outb(0x70, 0x17);
let low = crate::arch::x86_64::port::inb(0x71) as usize;
crate::arch::x86_64::port::outb(0x70, 0x18);
let high = crate::arch::x86_64::port::inb(0x71) as usize;
let extended_mem = (high << 8) | low; // in KB
1024 * 1024 + (extended_mem * 1024) // Base 1MB + extended
};
// Method 2: Try to probe memory (simplified)
let probe_memory = probe_memory_size();
// Use the larger of the two methods
let detected_memory = core::cmp::max(cmos_memory, probe_memory);
// Sanity check
if detected_memory < 16 * 1024 * 1024 {
Ok(64 * 1024 * 1024) // Default to 64MB
} else if detected_memory > 16 * 1024 * 1024 * 1024 {
Ok(8 * 1024 * 1024 * 1024) // Cap at 8GB
} else {
Ok(detected_memory)
}
}
/// Probe memory size by testing access
fn probe_memory_size() -> usize {
// Simplified memory probing - just return a reasonable default
// In a real implementation, this would carefully probe memory ranges
512 * 1024 * 1024 // 512MB default
}
/// Detect PCI devices
pub fn detect_pci_devices() -> Result<Vec<PciDevice>> {
let mut devices = Vec::new();
// Scan PCI bus 0 (simplified)
for device in 0..32 {
for function in 0..8 {
let vendor_id = pci_config_read(0, device, function, 0x00) as u16;
if vendor_id != 0xFFFF {
let device_id =
(pci_config_read(0, device, function, 0x00) >> 16) as u16;
let class_info = pci_config_read(0, device, function, 0x08);
let revision =
(pci_config_read(0, device, function, 0x08) & 0xFF) as u8;
let mut bars = [PciBar::new(); 6];
for i in 0..6 {
let bar_val = pci_config_read(
0,
device,
function,
0x10 + (i * 4),
);
if bar_val == 0 {
continue;
}
let is_io = bar_val & 1 != 0;
if is_io {
bars[i as usize].address =
(bar_val & 0xFFFFFFFC) as u64;
} else {
bars[i as usize].address =
(bar_val & 0xFFFFFFF0) as u64;
}
bars[i as usize].flags = bar_val & 0xF;
}
devices.push(PciDevice {
bus: 0,
slot: device,
function,
vendor: vendor_id,
device: device_id,
class: (class_info >> 16),
revision,
subsystem_vendor: 0, // Not implemented
subsystem_device: 0, // Not implemented
irq: 0, // Not implemented
bars,
});
}
}
}
Ok(devices)
}
/// Read PCI configuration space
pub(crate) fn pci_config_read(bus: u8, device: u8, function: u8, offset: u8) -> u32 {
let address = 0x80000000u32
| ((bus as u32) << 16)
| ((device as u32) << 11)
| ((function as u32) << 8)
| (offset as u32 & 0xFC);
unsafe {
crate::arch::x86_64::port::outl(0xCF8, address);
crate::arch::x86_64::port::inl(0xCFC)
}
}
/// Execute CPUID instruction (simplified to avoid RBX conflicts)
fn cpuid(leaf: u32) -> (u32, u32, u32, u32) {
// For now, return simplified values to avoid RBX register conflicts
match leaf {
0 => (0x0000000D, 0x756e6547, 0x6c65746e, 0x49656e69), // "GenuineIntel"
1 => (0x000906E9, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF), // Typical Intel CPU
0x80000000 => (0x80000008, 0, 0, 0),
0x80000002 => (0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865), /* "Intel(R) Core(TM" */
0x80000003 => (0x35692029, 0x3034332D, 0x20555043, 0x20402030), // ") i5-4340
// CPU @ "
0x80000004 => (0x30302E33, 0x007A4847, 0x00000000, 0x00000000), // "3.00GHz"
_ => (0, 0, 0, 0),
}
}
/// Convert u32 to 4-character string
fn u32_to_string(value: u32) -> String {
let bytes = value.to_le_bytes();
String::from_utf8_lossy(&bytes)
.trim_end_matches('\0')
.to_string()
}
/// Get system information
pub fn get_system_info() -> Result<SystemInfo> {
let cpu = detect_cpu()?;
let total_memory = detect_memory()?;
let pci_devices = detect_pci_devices()?;
Ok(SystemInfo {
cpu,
total_memory,
available_memory: (total_memory * 95) / 100,
boot_device: "Unknown".to_string(),
acpi_available: false, // TODO: Implement ACPI detection
pci_devices,
})
}

40
kernel/src/icmp.rs Archivo normal
Ver fichero

@@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-2.0
//! ICMP (Internet Control Message Protocol) implementation.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum IcmpType {
EchoReply = 0,
EchoRequest = 8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum IcmpCode {
Echo = 0,
}
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
pub struct IcmpPacket {
pub icmp_type: IcmpType,
pub icmp_code: IcmpCode,
pub checksum: u16,
pub identifier: u16,
pub sequence_number: u16,
}
impl IcmpPacket {
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.push(self.icmp_type as u8);
bytes.push(self.icmp_code as u8);
bytes.extend_from_slice(&self.checksum.to_be_bytes());
bytes.extend_from_slice(&self.identifier.to_be_bytes());
bytes.extend_from_slice(&self.sequence_number.to_be_bytes());
bytes
}
}

122
kernel/src/init.rs Archivo normal
Ver fichero

@@ -0,0 +1,122 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel initialization
use crate::error::Result;
/// Early kernel initialization
pub fn early_init() {
crate::console::write_str("[+] Early initialization complete\n");
}
/// Initialize all kernel subsystems
fn init_subsystems() {
crate::console::write_str("[*] Initializing kernel subsystems...\n");
// Initialize timer system
crate::console::write_str(" - Timer system\n");
if let Err(_e) = crate::timer::init_timer() {
crate::console::write_str(" [!] Timer init failed (non-fatal)\n");
}
// Initialize interrupt handlers
crate::console::write_str(" - Interrupt handlers\n");
if let Err(_e) = crate::interrupt::init() {
crate::console::write_str(" [!] Interrupt init failed (non-fatal)\n");
}
// Initialize scheduler
crate::console::write_str(" - Scheduler\n");
if let Err(_e) = crate::enhanced_scheduler::init_enhanced_scheduler() {
crate::console::write_str(" [!] Scheduler init failed (non-fatal)\n");
}
// Initialize IPC subsystem
crate::console::write_str(" - IPC subsystem\n");
if let Err(_e) = crate::ipc::init_ipc() {
crate::console::write_str(" [!] IPC init failed (non-fatal)\n");
}
// Initialize performance monitoring
crate::console::write_str(" - Performance monitoring\n");
if let Err(_e) = crate::advanced_perf::init_performance_monitoring() {
crate::console::write_str(" [!] Perf init failed (non-fatal)\n");
}
// Initialize diagnostics
crate::console::write_str(" - System diagnostics\n");
if let Err(_e) = crate::diagnostics::init_diagnostics() {
crate::console::write_str(" [!] Diagnostics init failed (non-fatal)\n");
}
// Initialize working task manager
crate::console::write_str(" - Task manager\n");
if let Err(_e) = crate::working_task::init_task_management() {
crate::console::write_str(" [!] Task mgmt init failed (non-fatal)\n");
}
crate::console::write_str("[+] Subsystems initialized\n");
}
/// Main kernel initialization
pub fn main_init() -> ! {
// Print boot banner
crate::console::write_str("\n");
crate::console::write_str("========================================\n");
crate::console::write_str(" Rust Kernel v0.1.0\n");
crate::console::write_str("========================================\n");
crate::console::write_str("\n");
// Initialize subsystems
init_subsystems();
// Print system information
crate::console::write_str("\n");
crate::console::write_str("System Information:\n");
crate::console::write_str(" Architecture: x86_64\n");
crate::console::write_str(" Memory mapping: 0-1GB identity mapped\n");
crate::console::write_str(" Page size: 2MB (large pages)\n");
crate::console::write_str("\n");
crate::console::write_str("[+] Kernel initialization complete\n");
crate::console::write_str("\n");
// Enter main kernel loop
main_kernel_loop()
}
/// Main kernel loop with task scheduling
fn main_kernel_loop() -> ! {
crate::console::write_str("Entering kernel main loop...\n");
let mut tick_count: u64 = 0;
loop {
tick_count = tick_count.wrapping_add(1);
// Handle timer tick periodically
if tick_count % 10000 == 0 {
crate::timer::handle_timer_tick();
}
// Schedule next task
if let Some(_tid) = crate::enhanced_scheduler::schedule_next() {
// Task would be executed here
for _ in 0..100 {
unsafe { core::arch::asm!("pause"); }
}
}
// Cleanup terminated tasks periodically
if tick_count % 100000 == 0 {
crate::working_task::cleanup_tasks();
}
// Heartbeat indicator
if tick_count % 5_000_000 == 0 {
crate::console::write_str(".");
}
// Halt CPU to save power
unsafe { core::arch::asm!("hlt"); }
}
}

465
kernel/src/interrupt.rs Archivo normal
Ver fichero

@@ -0,0 +1,465 @@
// SPDX-License-Identifier: GPL-2.0
//! Interrupt handling compatible with Linux kernel
use alloc::{boxed::Box, collections::BTreeMap}; // Add Box import
use core::arch::asm;
use core::fmt;
use core::sync::atomic::{AtomicU64, Ordering};
use crate::error::{Error, Result};
use crate::sync::Spinlock;
/// Global interrupt counter
static INTERRUPT_COUNT: AtomicU64 = AtomicU64::new(0);
/// Get total interrupt count
pub fn get_interrupt_count() -> u64 {
INTERRUPT_COUNT.load(Ordering::Relaxed)
}
/// Increment interrupt counter
pub fn increment_interrupt_count() {
INTERRUPT_COUNT.fetch_add(1, Ordering::Relaxed);
}
/// IRQ flags - compatible with Linux kernel
pub mod irq_flags {
pub const IRQF_SHARED: u32 = 0x00000080;
pub const IRQF_TRIGGER_NONE: u32 = 0x00000000;
pub const IRQF_TRIGGER_RISING: u32 = 0x00000001;
pub const IRQF_TRIGGER_FALLING: u32 = 0x00000002;
pub const IRQF_TRIGGER_HIGH: u32 = 0x00000004;
pub const IRQF_TRIGGER_LOW: u32 = 0x00000008;
pub const IRQF_ONESHOT: u32 = 0x00002000;
pub const IRQF_NO_SUSPEND: u32 = 0x00004000;
pub const IRQF_FORCE_RESUME: u32 = 0x00008000;
pub const IRQF_NO_THREAD: u32 = 0x00010000;
pub const IRQF_EARLY_RESUME: u32 = 0x00020000;
pub const IRQF_COND_SUSPEND: u32 = 0x00040000;
}
/// Interrupt return values - Linux compatible
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IrqReturn {
None, // IRQ_NONE
Handled, // IRQ_HANDLED
WakeThread, // IRQ_WAKE_THREAD
}
impl fmt::Display for IrqReturn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
IrqReturn::None => write!(f, "IRQ_NONE"),
IrqReturn::Handled => write!(f, "IRQ_HANDLED"),
IrqReturn::WakeThread => write!(f, "IRQ_WAKE_THREAD"),
}
}
}
/// Interrupt handler function type - Linux compatible
pub type IrqHandler = fn(irq: u32, dev_id: *mut u8) -> IrqReturn;
/// A wrapper for device pointer that can be safely shared between threads
/// In kernel code, we know the device pointer is valid for the lifetime of the
/// driver
#[derive(Debug)]
pub struct DevicePointer(*mut u8);
impl DevicePointer {
pub fn new(ptr: *mut u8) -> Self {
Self(ptr)
}
pub fn as_ptr(&self) -> *mut u8 {
self.0
}
}
// SAFETY: In kernel code, device pointers are managed by the kernel
// and are valid for the lifetime of the driver registration
unsafe impl Send for DevicePointer {}
unsafe impl Sync for DevicePointer {}
/// Interrupt action structure - similar to Linux irqaction
#[derive(Debug)]
pub struct IrqAction {
pub handler: IrqHandler,
pub flags: u32,
pub name: &'static str,
pub dev_id: DevicePointer,
pub next: Option<Box<IrqAction>>,
}
impl IrqAction {
pub fn new(handler: IrqHandler, flags: u32, name: &'static str, dev_id: *mut u8) -> Self {
Self {
handler,
flags,
name,
dev_id: DevicePointer::new(dev_id),
next: None,
}
}
}
/// Interrupt descriptor - similar to Linux irq_desc
#[derive(Debug)]
pub struct IrqDescriptor {
pub irq: u32,
pub action: Option<Box<IrqAction>>,
pub depth: u32, // nesting depth for disable/enable
pub wake_depth: u32, // wake nesting depth
pub irq_count: u64, // number of interrupts
pub irqs_unhandled: u64, // number of unhandled interrupts
pub name: &'static str,
pub status: u32,
}
impl IrqDescriptor {
pub fn new(irq: u32, name: &'static str) -> Self {
Self {
irq,
action: None,
depth: 1, // starts disabled
wake_depth: 0,
irq_count: 0,
irqs_unhandled: 0,
name,
status: 0,
}
}
pub fn is_enabled(&self) -> bool {
self.depth == 0
}
pub fn enable(&mut self) {
if self.depth > 0 {
self.depth -= 1;
}
}
pub fn disable(&mut self) {
self.depth += 1;
}
}
/// Global interrupt subsystem
static INTERRUPT_SUBSYSTEM: Spinlock<InterruptSubsystem> = Spinlock::new(InterruptSubsystem::new());
/// Interrupt subsystem state
struct InterruptSubsystem {
descriptors: BTreeMap<u32, IrqDescriptor>,
enabled: bool,
}
impl InterruptSubsystem {
const fn new() -> Self {
Self {
descriptors: BTreeMap::new(),
enabled: false,
}
}
fn add_descriptor(&mut self, desc: IrqDescriptor) {
let irq = desc.irq;
self.descriptors.insert(irq, desc);
}
fn get_descriptor_mut(&mut self, irq: u32) -> Option<&mut IrqDescriptor> {
self.descriptors.get_mut(&irq)
}
#[allow(dead_code)]
fn get_descriptor(&self, irq: u32) -> Option<&IrqDescriptor> {
self.descriptors.get(&irq)
}
}
/// Initialize interrupt handling
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()?;
subsystem.enabled = true;
crate::info!("Interrupt subsystem initialized");
Ok(())
}
/// Initialize standard x86 interrupts
fn init_standard_interrupts(subsystem: &mut InterruptSubsystem) -> Result<()> {
// Timer interrupt (IRQ 0)
let timer_desc = IrqDescriptor::new(0, "timer");
subsystem.add_descriptor(timer_desc);
// Keyboard interrupt (IRQ 1)
let keyboard_desc = IrqDescriptor::new(1, "keyboard");
subsystem.add_descriptor(keyboard_desc);
// Cascade for slave PIC (IRQ 2)
let cascade_desc = IrqDescriptor::new(2, "cascade");
subsystem.add_descriptor(cascade_desc);
// Serial port 2/4 (IRQ 3)
let serial_desc = IrqDescriptor::new(3, "serial");
subsystem.add_descriptor(serial_desc);
// Serial port 1/3 (IRQ 4)
let serial2_desc = IrqDescriptor::new(4, "serial");
subsystem.add_descriptor(serial2_desc);
// Parallel port (IRQ 7)
let parallel_desc = IrqDescriptor::new(7, "parallel");
subsystem.add_descriptor(parallel_desc);
// Real-time clock (IRQ 8)
let rtc_desc = IrqDescriptor::new(8, "rtc");
subsystem.add_descriptor(rtc_desc);
// Mouse (IRQ 12)
let mouse_desc = IrqDescriptor::new(12, "mouse");
subsystem.add_descriptor(mouse_desc);
// IDE primary (IRQ 14)
let ide1_desc = IrqDescriptor::new(14, "ide");
subsystem.add_descriptor(ide1_desc);
// IDE secondary (IRQ 15)
let ide2_desc = IrqDescriptor::new(15, "ide");
subsystem.add_descriptor(ide2_desc);
Ok(())
}
/// Initialize interrupt controller
fn init_interrupt_controller() -> Result<()> {
// TODO: Initialize PIC or APIC
// For now, just set up basic PIC configuration
unsafe {
// Remap PIC interrupts to avoid conflicts with CPU exceptions
crate::arch::x86_64::pic::init_pic();
}
Ok(())
}
/// Initialize exception handlers
fn init_exception_handlers() -> Result<()> {
// Architecture-specific IDT initialization is done in init()
Ok(())
}
/// Register an interrupt handler - Linux compatible
pub fn request_irq(
irq: u32,
handler: IrqHandler,
flags: u32,
name: &'static str,
dev_id: *mut u8,
) -> Result<()> {
let mut subsystem = INTERRUPT_SUBSYSTEM.lock();
if let Some(desc) = subsystem.get_descriptor_mut(irq) {
let action = IrqAction::new(handler, flags, name, dev_id);
// Check if IRQ is shared
if flags & irq_flags::IRQF_SHARED != 0 {
// Add to action chain
let mut current = &mut desc.action;
while let Some(ref mut act) = current {
current = &mut act.next;
}
*current = Some(Box::new(action));
} else {
// Replace existing action
desc.action = Some(Box::new(action));
}
// Enable the interrupt
desc.enable();
crate::info!("Registered IRQ {} handler: {}", irq, name);
Ok(())
} else {
Err(Error::InvalidArgument)
}
}
/// Unregister an interrupt handler - Linux compatible
pub fn free_irq(irq: u32, dev_id: *mut u8) -> Result<()> {
let mut subsystem = INTERRUPT_SUBSYSTEM.lock();
if let Some(desc) = subsystem.get_descriptor_mut(irq) {
// Remove action with matching dev_id
let prev: Option<&mut Box<IrqAction>> = None;
let current = &mut desc.action;
let mut found = false;
// Handle first element specially
if let Some(ref mut action) = current {
if action.dev_id.as_ptr() == dev_id {
*current = action.next.take();
found = true;
} else {
// Search in the chain
let mut node = current.as_mut().unwrap();
while let Some(ref mut next_action) = node.next {
if next_action.dev_id.as_ptr() == dev_id {
node.next = next_action.next.take();
found = true;
break;
}
node = node.next.as_mut().unwrap();
}
}
}
if found {
// If no more actions, disable the interrupt
if desc.action.is_none() {
desc.disable();
}
crate::info!("Freed IRQ {} handler", irq);
Ok(())
} else {
Err(Error::NotFound)
}
} else {
Err(Error::InvalidArgument)
}
}
/// Enable interrupts globally
pub fn enable() {
#[cfg(target_arch = "x86_64")]
unsafe {
core::arch::asm!("sti");
}
}
/// Disable interrupts globally
pub fn disable() {
#[cfg(target_arch = "x86_64")]
unsafe {
core::arch::asm!("cli");
}
}
/// Enable a specific interrupt line
pub fn enable_irq(irq: u32) -> Result<()> {
let mut subsystem = INTERRUPT_SUBSYSTEM.lock();
if let Some(desc) = subsystem.get_descriptor_mut(irq) {
desc.enable();
crate::debug!("Enabled IRQ {}", irq);
Ok(())
} else {
Err(Error::InvalidArgument)
}
}
/// Disable a specific interrupt line
pub fn disable_irq(irq: u32) -> Result<()> {
let mut subsystem = INTERRUPT_SUBSYSTEM.lock();
if let Some(desc) = subsystem.get_descriptor_mut(irq) {
desc.disable();
crate::debug!("Disabled IRQ {}", irq);
Ok(())
} else {
Err(Error::InvalidArgument)
}
}
/// 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);
}
crate::info!(
"Registered interrupt handler at vector 0x{:x} -> 0x{:x}",
vector,
handler
);
Ok(())
}
// Exception handlers
/// System call interrupt handler
#[no_mangle]
pub extern "C" fn syscall_handler() {
// TODO: Get syscall arguments from registers
// In x86_64, syscall arguments are passed in:
// rax = syscall number
// rdi = arg0, rsi = arg1, rdx = arg2, r10 = arg3, r8 = arg4, r9 = arg5
let mut syscall_num: u64;
let mut arg0: u64;
let mut arg1: u64;
let mut arg2: u64;
let mut arg3: u64;
let mut arg4: u64;
let mut arg5: u64;
unsafe {
core::arch::asm!(
"mov {0}, rax",
"mov {1}, rdi",
"mov {2}, rsi",
"mov {3}, rdx",
"mov {4}, r10",
"mov {5}, r8",
"mov {6}, r9",
out(reg) syscall_num,
out(reg) arg0,
out(reg) arg1,
out(reg) arg2,
out(reg) arg3,
out(reg) arg4,
out(reg) arg5,
);
}
// Call syscall dispatcher
let result = crate::syscalls::arch::syscall_entry(
syscall_num,
arg0,
arg1,
arg2,
arg3,
arg4,
arg5,
);
// Return result in register (rax)
unsafe {
core::arch::asm!(
"mov rax, {0}",
in(reg) result,
);
// Return from interrupt
core::arch::asm!("iretq", options(noreturn));
}
}
/// Install syscall interrupt handler
pub fn install_syscall_handler() -> Result<()> {
// Install at interrupt vector 0x80 (traditional Linux syscall vector)
register_interrupt_handler(0x80, syscall_handler as usize)?;
// TODO: Also set up SYSCALL/SYSRET for x86_64
Ok(())
}

482
kernel/src/ipc.rs Archivo normal
Ver fichero

@@ -0,0 +1,482 @@
// SPDX-License-Identifier: GPL-2.0
//! Advanced Inter-Process Communication (IPC) system
use alloc::{
collections::{BTreeMap, VecDeque},
string::String,
vec::Vec,
};
use core::sync::atomic::{AtomicU64, Ordering};
use crate::error::{Error, Result};
use crate::sync::Spinlock;
use crate::types::Tid;
/// IPC message types
#[derive(Debug, Clone, PartialEq)]
pub enum MessageType {
Data,
Signal,
Request,
Response,
Broadcast,
Priority,
}
/// IPC message structure
#[derive(Debug, Clone)]
pub struct Message {
pub id: u64,
pub sender: Tid,
pub recipient: Tid,
pub msg_type: MessageType,
pub data: Vec<u8>,
pub timestamp: u64,
pub priority: u8,
}
/// Message queue for a process
#[derive(Debug)]
pub struct MessageQueue {
pub messages: VecDeque<Message>,
pub max_size: usize,
pub blocked_senders: Vec<Tid>,
pub blocked_receivers: Vec<Tid>,
}
impl MessageQueue {
pub fn new(max_size: usize) -> Self {
Self {
messages: VecDeque::new(),
max_size,
blocked_senders: Vec::new(),
blocked_receivers: Vec::new(),
}
}
pub fn is_full(&self) -> bool {
self.messages.len() >= self.max_size
}
pub fn is_empty(&self) -> bool {
self.messages.is_empty()
}
}
/// Semaphore for synchronization
#[derive(Debug)]
pub struct Semaphore {
pub value: i32,
pub waiting_tasks: VecDeque<Tid>,
}
impl Semaphore {
pub fn new(initial_value: i32) -> Self {
Self {
value: initial_value,
waiting_tasks: VecDeque::new(),
}
}
}
/// Shared memory region
#[derive(Debug)]
pub struct SharedMemory {
pub id: u64,
pub size: usize,
pub address: usize,
pub owners: Vec<Tid>,
pub permissions: u32,
pub ref_count: usize,
}
/// IPC statistics
#[derive(Debug, Default)]
pub struct IpcStats {
pub messages_sent: AtomicU64,
pub messages_received: AtomicU64,
pub semaphore_operations: AtomicU64,
pub shared_memory_attachments: AtomicU64,
pub pipe_operations: AtomicU64,
}
/// Advanced IPC manager
pub struct IpcManager {
message_queues: Spinlock<BTreeMap<Tid, MessageQueue>>,
semaphores: Spinlock<BTreeMap<u64, Semaphore>>,
shared_memory: Spinlock<BTreeMap<u64, SharedMemory>>,
pipes: Spinlock<BTreeMap<u64, VecDeque<u8>>>,
next_message_id: AtomicU64,
next_semaphore_id: AtomicU64,
next_shm_id: AtomicU64,
next_pipe_id: AtomicU64,
stats: IpcStats,
}
impl IpcManager {
pub const fn new() -> Self {
Self {
message_queues: Spinlock::new(BTreeMap::new()),
semaphores: Spinlock::new(BTreeMap::new()),
shared_memory: Spinlock::new(BTreeMap::new()),
pipes: Spinlock::new(BTreeMap::new()),
next_message_id: AtomicU64::new(1),
next_semaphore_id: AtomicU64::new(1),
next_shm_id: AtomicU64::new(1),
next_pipe_id: AtomicU64::new(1),
stats: IpcStats {
messages_sent: AtomicU64::new(0),
messages_received: AtomicU64::new(0),
semaphore_operations: AtomicU64::new(0),
shared_memory_attachments: AtomicU64::new(0),
pipe_operations: AtomicU64::new(0),
},
}
}
/// Create message queue for a process
pub fn create_message_queue(&self, tid: Tid, max_size: usize) -> Result<()> {
let mut queues = self.message_queues.lock();
if queues.contains_key(&tid) {
return Err(Error::AlreadyExists);
}
queues.insert(tid, MessageQueue::new(max_size));
Ok(())
}
/// Send message to another process
pub fn send_message(
&self,
sender: Tid,
recipient: Tid,
msg_type: MessageType,
data: Vec<u8>,
priority: u8,
) -> Result<u64> {
let message_id = self.next_message_id.fetch_add(1, Ordering::Relaxed);
let message = Message {
id: message_id,
sender,
recipient,
msg_type,
data,
timestamp: crate::time::get_jiffies().0,
priority,
};
let mut queues = self.message_queues.lock();
match queues.get_mut(&recipient) {
Some(queue) => {
if queue.is_full() {
// Queue is full, block sender or return error
return Err(Error::ResourceBusy);
}
// Insert message in priority order
let insert_pos = queue
.messages
.iter()
.position(|m| m.priority < priority)
.unwrap_or(queue.messages.len());
queue.messages.insert(insert_pos, message);
self.stats.messages_sent.fetch_add(1, Ordering::Relaxed);
Ok(message_id)
}
None => Err(Error::NotFound),
}
}
/// Receive message from queue
pub fn receive_message(&self, tid: Tid) -> Result<Option<Message>> {
let mut queues = self.message_queues.lock();
match queues.get_mut(&tid) {
Some(queue) => {
if let Some(message) = queue.messages.pop_front() {
self.stats
.messages_received
.fetch_add(1, Ordering::Relaxed);
Ok(Some(message))
} else {
Ok(None)
}
}
None => Err(Error::NotFound),
}
}
/// Create semaphore
pub fn create_semaphore(&self, initial_value: i32) -> Result<u64> {
let sem_id = self.next_semaphore_id.fetch_add(1, Ordering::Relaxed);
let mut semaphores = self.semaphores.lock();
semaphores.insert(sem_id, Semaphore::new(initial_value));
Ok(sem_id)
}
/// Wait on semaphore (P operation)
pub fn semaphore_wait(&self, sem_id: u64, tid: Tid) -> Result<bool> {
let mut semaphores = self.semaphores.lock();
match semaphores.get_mut(&sem_id) {
Some(semaphore) => {
if semaphore.value > 0 {
semaphore.value -= 1;
self.stats
.semaphore_operations
.fetch_add(1, Ordering::Relaxed);
Ok(true) // Acquired immediately
} else {
semaphore.waiting_tasks.push_back(tid);
Ok(false) // Would block
}
}
None => Err(Error::NotFound),
}
}
/// Signal semaphore (V operation)
pub fn semaphore_signal(&self, sem_id: u64) -> Result<Option<Tid>> {
let mut semaphores = self.semaphores.lock();
match semaphores.get_mut(&sem_id) {
Some(semaphore) => {
semaphore.value += 1;
let woken_task = semaphore.waiting_tasks.pop_front();
if woken_task.is_some() {
semaphore.value -= 1; // Task will consume the signal
}
self.stats
.semaphore_operations
.fetch_add(1, Ordering::Relaxed);
Ok(woken_task)
}
None => Err(Error::NotFound),
}
}
/// Create shared memory region
pub fn create_shared_memory(&self, size: usize, permissions: u32) -> Result<u64> {
let shm_id = self.next_shm_id.fetch_add(1, Ordering::Relaxed);
// Allocate memory (simplified - in reality would use page allocator)
let address = crate::memory::kmalloc::kmalloc(size)?;
let shm = SharedMemory {
id: shm_id,
size,
address: address as usize,
owners: Vec::new(),
permissions,
ref_count: 0,
};
let mut shared_memory = self.shared_memory.lock();
shared_memory.insert(shm_id, shm);
Ok(shm_id)
}
/// Attach to shared memory
pub fn attach_shared_memory(&self, shm_id: u64, tid: Tid) -> Result<usize> {
let mut shared_memory = self.shared_memory.lock();
match shared_memory.get_mut(&shm_id) {
Some(shm) => {
if !shm.owners.contains(&tid) {
shm.owners.push(tid);
shm.ref_count += 1;
}
self.stats
.shared_memory_attachments
.fetch_add(1, Ordering::Relaxed);
Ok(shm.address)
}
None => Err(Error::NotFound),
}
}
/// Create pipe
pub fn create_pipe(&self) -> Result<u64> {
let pipe_id = self.next_pipe_id.fetch_add(1, Ordering::Relaxed);
let mut pipes = self.pipes.lock();
pipes.insert(pipe_id, VecDeque::new());
Ok(pipe_id)
}
/// Write to pipe
pub fn pipe_write(&self, pipe_id: u64, data: &[u8]) -> Result<usize> {
let mut pipes = self.pipes.lock();
match pipes.get_mut(&pipe_id) {
Some(pipe) => {
pipe.extend(data.iter().cloned());
self.stats.pipe_operations.fetch_add(1, Ordering::Relaxed);
Ok(data.len())
}
None => Err(Error::NotFound),
}
}
/// Read from pipe
pub fn pipe_read(&self, pipe_id: u64, buffer: &mut [u8]) -> Result<usize> {
let mut pipes = self.pipes.lock();
match pipes.get_mut(&pipe_id) {
Some(pipe) => {
let read_len = buffer.len().min(pipe.len());
for i in 0..read_len {
buffer[i] = pipe.pop_front().unwrap();
}
self.stats.pipe_operations.fetch_add(1, Ordering::Relaxed);
Ok(read_len)
}
None => Err(Error::NotFound),
}
}
/// Get IPC statistics
pub fn get_stats(&self) -> IpcStatsSnapshot {
IpcStatsSnapshot {
messages_sent: self.stats.messages_sent.load(Ordering::Relaxed),
messages_received: self.stats.messages_received.load(Ordering::Relaxed),
semaphore_operations: self
.stats
.semaphore_operations
.load(Ordering::Relaxed),
shared_memory_attachments: self
.stats
.shared_memory_attachments
.load(Ordering::Relaxed),
pipe_operations: self.stats.pipe_operations.load(Ordering::Relaxed),
active_queues: self.message_queues.lock().len(),
active_semaphores: self.semaphores.lock().len(),
active_shared_memory: self.shared_memory.lock().len(),
active_pipes: self.pipes.lock().len(),
}
}
/// Cleanup resources for a terminated process
pub fn cleanup_process(&self, tid: Tid) -> Result<()> {
// Remove message queue
self.message_queues.lock().remove(&tid);
// Remove from semaphore waiting lists
let mut semaphores = self.semaphores.lock();
for semaphore in semaphores.values_mut() {
semaphore.waiting_tasks.retain(|&t| t != tid);
}
// Detach from shared memory
let mut shared_memory = self.shared_memory.lock();
let mut to_remove = Vec::new();
for (id, shm) in shared_memory.iter_mut() {
if let Some(pos) = shm.owners.iter().position(|&t| t == tid) {
shm.owners.remove(pos);
shm.ref_count -= 1;
if shm.ref_count == 0 {
to_remove.push(*id);
}
}
}
// Free unused shared memory
for id in to_remove {
if let Some(shm) = shared_memory.remove(&id) {
unsafe {
crate::memory::kmalloc::kfree(shm.address as *mut u8);
}
}
}
Ok(())
}
}
/// IPC statistics snapshot
#[derive(Debug, Clone)]
pub struct IpcStatsSnapshot {
pub messages_sent: u64,
pub messages_received: u64,
pub semaphore_operations: u64,
pub shared_memory_attachments: u64,
pub pipe_operations: u64,
pub active_queues: usize,
pub active_semaphores: usize,
pub active_shared_memory: usize,
pub active_pipes: usize,
}
/// Global IPC manager
static IPC_MANAGER: IpcManager = IpcManager::new();
/// Initialize IPC system
pub fn init_ipc() -> Result<()> {
crate::info!("IPC system initialized");
Ok(())
}
/// Create message queue for process
pub fn create_message_queue(tid: Tid, max_size: usize) -> Result<()> {
IPC_MANAGER.create_message_queue(tid, max_size)
}
/// Send message
pub fn send_message(
sender: Tid,
recipient: Tid,
msg_type: MessageType,
data: Vec<u8>,
priority: u8,
) -> Result<u64> {
IPC_MANAGER.send_message(sender, recipient, msg_type, data, priority)
}
/// Receive message
pub fn receive_message(tid: Tid) -> Result<Option<Message>> {
IPC_MANAGER.receive_message(tid)
}
/// Create semaphore
pub fn create_semaphore(initial_value: i32) -> Result<u64> {
IPC_MANAGER.create_semaphore(initial_value)
}
/// Wait on semaphore
pub fn semaphore_wait(sem_id: u64, tid: Tid) -> Result<bool> {
IPC_MANAGER.semaphore_wait(sem_id, tid)
}
/// Signal semaphore
pub fn semaphore_signal(sem_id: u64) -> Result<Option<Tid>> {
IPC_MANAGER.semaphore_signal(sem_id)
}
/// Create shared memory
pub fn create_shared_memory(size: usize, permissions: u32) -> Result<u64> {
IPC_MANAGER.create_shared_memory(size, permissions)
}
/// Attach to shared memory
pub fn attach_shared_memory(shm_id: u64, tid: Tid) -> Result<usize> {
IPC_MANAGER.attach_shared_memory(shm_id, tid)
}
/// Create pipe
pub fn create_pipe() -> Result<u64> {
IPC_MANAGER.create_pipe()
}
/// Write to pipe
pub fn pipe_write(pipe_id: u64, data: &[u8]) -> Result<usize> {
IPC_MANAGER.pipe_write(pipe_id, data)
}
/// Read from pipe
pub fn pipe_read(pipe_id: u64, buffer: &mut [u8]) -> Result<usize> {
IPC_MANAGER.pipe_read(pipe_id, buffer)
}
/// Get IPC statistics
pub fn get_ipc_stats() -> IpcStatsSnapshot {
IPC_MANAGER.get_stats()
}
/// Cleanup process IPC resources
pub fn cleanup_process_ipc(tid: Tid) -> Result<()> {
IPC_MANAGER.cleanup_process(tid)
}

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

@@ -0,0 +1,193 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel thread management
use alloc::{boxed::Box, string::String, vec::Vec};
use core::sync::atomic::{AtomicU32, Ordering};
use crate::error::Result;
use crate::sync::Spinlock;
use crate::{error, info};
/// 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())
}

170
kernel/src/lib.rs Archivo normal
Ver fichero

@@ -0,0 +1,170 @@
// SPDX-License-Identifier: GPL-2.0
//! The Rust kernel crate.
//!
//! This crate provides the core kernel APIs and functionality for the Rust
//! kernel. It is inspired by the Linux kernel's Rust infrastructure but
//! designed as a standalone kernel implementation.
#![no_std]
#![feature(alloc_error_handler)]
#![feature(panic_info_message)]
#![feature(asm_const)]
#![feature(const_mut_refs)]
#![feature(custom_test_frameworks)]
#![feature(allocator_api)]
#![test_runner(crate::test_runner)]
#![reexport_test_harness_main = "test_main"]
extern crate alloc;
// Include boot assembly
// #[cfg(target_arch = "x86_64")]
// global_asm!(include_str!("arch/x86_64/boot.s"), options(att_syntax));
pub mod advanced_perf; // Advanced performance monitoring and profiling
pub mod arch;
pub mod arp;
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 enhanced_scheduler; // Enhanced preemptive scheduler
pub mod error;
pub mod fs;
pub mod hardware; // Hardware detection and initialization
pub mod icmp;
pub mod init;
pub mod interrupt;
pub mod ipc; // Inter-process communication
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 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 test_suite; // Comprehensive kernel test suite
pub mod time;
pub mod timer; // Timer interrupt and preemptive scheduling
pub mod types;
pub mod usermode;
pub mod working_task; // Working kernel task implementation // User mode program support
/// Kernel version information
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();
// Should not return from main_init
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 && multiboot_magic != 0x2BADB002 {
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 {}
}
crate::console::write_str("\n");
crate::console::write_str("Booting Rust Kernel...\n");
}
/// Initialize memory management using multiboot information
fn memory_init() -> Result<(), error::Error> {
crate::console::write_str("[*] Initializing memory subsystem...\n");
// FIXME: Multiboot parsing causes crashes - use default memory layout for now
memory::page::init()?;
// Initialize heap allocator
memory::kmalloc::init()?;
crate::console::write_str("[+] Memory subsystem ready\n");
Ok(())
}
/// Test runner for kernel tests
#[cfg(test)]
fn test_runner(tests: &[&dyn Fn()]) {
println!("Running {} tests", tests.len());
for test in tests {
test();
}
exit_qemu(QemuExitCode::Success);
}
#[cfg(test)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum QemuExitCode {
Success = 0x10,
Failed = 0x11,
}
#[cfg(test)]
pub fn exit_qemu(exit_code: QemuExitCode) {
use arch::x86_64::port::Port;
unsafe {
let mut port = Port::new(0xf4);
port.write(exit_code as u32);
}
}
/// Global allocator error handler
#[alloc_error_handler]
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
panic!("allocation error: {:?}", layout)
}

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

@@ -0,0 +1,488 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel logging and debugging system
use alloc::{format, string::String, vec, vec::Vec};
use core::fmt::Write;
use crate::error::Result;
use crate::sync::Spinlock;
use crate::time::get_jiffies;
/// 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");
}
}

29
kernel/src/main.rs Archivo normal
Ver fichero

@@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel main entry point
#![no_std]
#![no_main]
extern crate kernel;
use core::arch::global_asm;
// Include boot assembly
#[cfg(target_arch = "x86_64")]
global_asm!(include_str!("arch/x86_64/boot.s"), options(att_syntax));
/// Entry point called by boot.s assembly code
/// This is just a wrapper to ensure the kernel crate is linked
#[no_mangle]
pub extern "C" fn rust_main() -> ! {
// This function shouldn't be called directly if boot.s calls kernel_main_multiboot
// But if it is called, we redirect to the kernel library
loop {
unsafe {
core::arch::asm!("hlt");
}
}
}
// Panic handler is defined in the kernel library

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

@@ -0,0 +1,501 @@
// SPDX-License-Identifier: GPL-2.0
//! Simple in-memory file system
use alloc::{
boxed::Box,
collections::BTreeMap,
string::{String, ToString},
vec,
vec::Vec,
};
use crate::error::Result;
use crate::sync::Spinlock;
use crate::{error, info, warn};
/// File type
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FileType {
RegularFile,
Directory,
SymbolicLink,
CharDevice,
BlockDevice,
}
/// File permissions (simplified)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FileMode(pub u32);
impl FileMode {
pub const READ: u32 = 0o444;
pub const WRITE: u32 = 0o222;
pub const EXECUTE: u32 = 0o111;
pub const ALL: u32 = 0o777;
pub fn new(mode: u32) -> Self {
Self(mode)
}
pub fn can_read(&self) -> bool {
self.0 & Self::READ != 0
}
pub fn can_write(&self) -> bool {
self.0 & Self::WRITE != 0
}
pub fn can_execute(&self) -> bool {
self.0 & Self::EXECUTE != 0
}
}
/// In-memory file node
#[derive(Debug)]
pub struct MemFile {
pub name: String,
pub file_type: FileType,
pub mode: FileMode,
pub size: usize,
pub data: Vec<u8>,
pub children: BTreeMap<String, Box<MemFile>>,
pub parent: Option<String>,
}
impl MemFile {
pub fn new_file(name: String, mode: FileMode) -> Self {
Self {
name,
file_type: FileType::RegularFile,
mode,
size: 0,
data: Vec::new(),
children: BTreeMap::new(),
parent: None,
}
}
pub fn new_dir(name: String, mode: FileMode) -> Self {
Self {
name,
file_type: FileType::Directory,
mode,
size: 0,
data: Vec::new(),
children: BTreeMap::new(),
parent: None,
}
}
pub fn is_dir(&self) -> bool {
self.file_type == FileType::Directory
}
pub fn is_file(&self) -> bool {
self.file_type == FileType::RegularFile
}
/// Write data to file
pub fn write(&mut self, data: &[u8]) -> Result<usize> {
if !self.mode.can_write() {
return Err(crate::error::Error::PermissionDenied);
}
if !self.is_file() {
return Err(crate::error::Error::InvalidOperation);
}
self.data.extend_from_slice(data);
self.size = self.data.len();
Ok(data.len())
}
/// Read data from file
pub fn read(&self, offset: usize, buffer: &mut [u8]) -> Result<usize> {
if !self.mode.can_read() {
return Err(crate::error::Error::PermissionDenied);
}
if !self.is_file() {
return Err(crate::error::Error::InvalidOperation);
}
if offset >= self.data.len() {
return Ok(0);
}
let available = self.data.len() - offset;
let to_read = buffer.len().min(available);
buffer[..to_read].copy_from_slice(&self.data[offset..offset + to_read]);
Ok(to_read)
}
/// Add child to directory
pub fn add_child(&mut self, child: MemFile) -> Result<()> {
if !self.is_dir() {
return Err(crate::error::Error::InvalidOperation);
}
let name = child.name.clone();
self.children.insert(name, Box::new(child));
Ok(())
}
/// Remove child from directory
pub fn remove_child(&mut self, name: &str) -> Result<()> {
if !self.is_dir() {
return Err(crate::error::Error::InvalidOperation);
}
if self.children.remove(name).is_some() {
Ok(())
} else {
Err(crate::error::Error::NotFound)
}
}
/// Get child by name
pub fn get_child(&self, name: &str) -> Option<&MemFile> {
self.children.get(name).map(|f| f.as_ref())
}
/// Get child by name (mutable)
pub fn get_child_mut(&mut self, name: &str) -> Option<&mut MemFile> {
self.children.get_mut(name).map(|f| f.as_mut())
}
/// List directory contents
pub fn list_children(&self) -> Vec<&str> {
if !self.is_dir() {
return Vec::new();
}
self.children.keys().map(|s| s.as_str()).collect()
}
}
/// Simple in-memory file system
pub struct MemFileSystem {
root: MemFile,
current_dir: String,
}
impl MemFileSystem {
pub fn new() -> Self {
let root = MemFile::new_dir("/".to_string(), FileMode::new(FileMode::ALL));
Self {
root,
current_dir: "/".to_string(),
}
}
/// Initialize with some default files
pub fn init_default_files(&mut self) -> Result<()> {
// Create /proc directory
let proc_dir = MemFile::new_dir(
"proc".to_string(),
FileMode::new(FileMode::READ | FileMode::EXECUTE),
);
self.root.add_child(proc_dir)?;
// Create /tmp directory
let tmp_dir = MemFile::new_dir("tmp".to_string(), FileMode::new(FileMode::ALL));
self.root.add_child(tmp_dir)?;
// Create /dev directory
let dev_dir = MemFile::new_dir("dev".to_string(), FileMode::new(FileMode::ALL));
self.root.add_child(dev_dir)?;
// Create some example files
let mut readme =
MemFile::new_file("README.txt".to_string(), FileMode::new(FileMode::READ));
readme.write(
b"Welcome to the Rust Kernel!\nThis is a simple in-memory file system.\n",
)?;
self.root.add_child(readme)?;
let mut version =
MemFile::new_file("version".to_string(), FileMode::new(FileMode::READ));
version.write(crate::VERSION.as_bytes())?;
self.root.add_child(version)?;
info!("Default file system structure created");
Ok(())
}
/// Resolve path to file
fn resolve_path(&self, path: &str) -> Option<&MemFile> {
if path == "/" {
return Some(&self.root);
}
let parts: Vec<&str> = path.trim_start_matches('/').split('/').collect();
let mut current = &self.root;
for part in parts {
if part.is_empty() {
continue;
}
current = current.get_child(part)?;
}
Some(current)
}
/// Resolve path to file (mutable)
fn resolve_path_mut(&mut self, path: &str) -> Option<&mut MemFile> {
if path == "/" {
return Some(&mut self.root);
}
let parts: Vec<&str> = path.trim_start_matches('/').split('/').collect();
let mut current = &mut self.root;
for part in parts {
if part.is_empty() {
continue;
}
current = current.get_child_mut(part)?;
}
Some(current)
}
/// Create a file
pub fn create_file(&mut self, path: &str, mode: FileMode) -> Result<()> {
let (dir_path, filename) = self.split_path(path);
if let Some(dir) = self.resolve_path_mut(&dir_path) {
if !dir.is_dir() {
return Err(crate::error::Error::InvalidOperation);
}
let file = MemFile::new_file(filename, mode);
dir.add_child(file)?;
Ok(())
} else {
Err(crate::error::Error::NotFound)
}
}
/// Create a directory
pub fn create_dir(&mut self, path: &str, mode: FileMode) -> Result<()> {
let (dir_path, dirname) = self.split_path(path);
if let Some(dir) = self.resolve_path_mut(&dir_path) {
if !dir.is_dir() {
return Err(crate::error::Error::InvalidOperation);
}
let new_dir = MemFile::new_dir(dirname, mode);
dir.add_child(new_dir)?;
Ok(())
} else {
Err(crate::error::Error::NotFound)
}
}
/// Write to a file
pub fn write_file(&mut self, path: &str, data: &[u8]) -> Result<usize> {
if let Some(file) = self.resolve_path_mut(path) {
file.write(data)
} else {
Err(crate::error::Error::NotFound)
}
}
/// Read from a file
pub fn read_file(&self, path: &str, offset: usize, buffer: &mut [u8]) -> Result<usize> {
if let Some(file) = self.resolve_path(path) {
file.read(offset, buffer)
} else {
Err(crate::error::Error::NotFound)
}
}
/// List directory contents
pub fn list_dir(&self, path: &str) -> Result<Vec<(String, FileType, usize)>> {
if let Some(dir) = self.resolve_path(path) {
if !dir.is_dir() {
return Err(crate::error::Error::InvalidOperation);
}
let mut entries = Vec::new();
for (name, child) in &dir.children {
entries.push((name.clone(), child.file_type, child.size));
}
Ok(entries)
} else {
Err(crate::error::Error::NotFound)
}
}
/// Remove a file or directory
pub fn remove(&mut self, path: &str) -> Result<()> {
let (dir_path, filename) = self.split_path(path);
if let Some(dir) = self.resolve_path_mut(&dir_path) {
dir.remove_child(&filename)
} else {
Err(crate::error::Error::NotFound)
}
}
/// Get file info
pub fn stat(&self, path: &str) -> Result<(FileType, FileMode, usize)> {
if let Some(file) = self.resolve_path(path) {
Ok((file.file_type, file.mode, file.size))
} else {
Err(crate::error::Error::NotFound)
}
}
/// Split path into directory and filename
fn split_path(&self, path: &str) -> (String, String) {
if let Some(pos) = path.rfind('/') {
let dir = if pos == 0 { "/" } else { &path[..pos] };
let file = &path[pos + 1..];
(dir.to_string(), file.to_string())
} else {
("/".to_string(), path.to_string())
}
}
}
/// Global file system instance
static FILESYSTEM: Spinlock<Option<MemFileSystem>> = Spinlock::new(None);
/// Initialize the in-memory file system
pub fn init_memfs() -> Result<()> {
info!("Initializing in-memory file system");
let mut fs = MemFileSystem::new();
fs.init_default_files()?;
let mut filesystem = FILESYSTEM.lock();
*filesystem = Some(fs);
info!("In-memory file system initialized");
Ok(())
}
/// File system operations for shell
pub fn fs_list(path: &str) -> Result<Vec<(String, FileType, usize)>> {
let filesystem = FILESYSTEM.lock();
if let Some(ref fs) = *filesystem {
fs.list_dir(path)
} else {
Err(crate::error::Error::NotInitialized)
}
}
pub fn fs_read(path: &str) -> Result<Vec<u8>> {
let filesystem = FILESYSTEM.lock();
if let Some(ref fs) = *filesystem {
let mut buffer = vec![0u8; 4096]; // Read up to 4KB
let bytes_read = fs.read_file(path, 0, &mut buffer)?;
buffer.truncate(bytes_read);
Ok(buffer)
} else {
Err(crate::error::Error::NotInitialized)
}
}
pub fn fs_write(path: &str, data: &[u8]) -> Result<usize> {
let mut filesystem = FILESYSTEM.lock();
if let Some(ref mut fs) = *filesystem {
fs.write_file(path, data)
} else {
Err(crate::error::Error::NotInitialized)
}
}
pub fn fs_create_file(path: &str) -> Result<()> {
let mut filesystem = FILESYSTEM.lock();
if let Some(ref mut fs) = *filesystem {
fs.create_file(path, FileMode::new(FileMode::READ | FileMode::WRITE))
} else {
Err(crate::error::Error::NotInitialized)
}
}
pub fn fs_create_dir(path: &str) -> Result<()> {
let mut filesystem = FILESYSTEM.lock();
if let Some(ref mut fs) = *filesystem {
fs.create_dir(path, FileMode::new(FileMode::ALL))
} else {
Err(crate::error::Error::NotInitialized)
}
}
pub fn fs_remove(path: &str) -> Result<()> {
let mut filesystem = FILESYSTEM.lock();
if let Some(ref mut fs) = *filesystem {
fs.remove(path)
} else {
Err(crate::error::Error::NotInitialized)
}
}
pub fn fs_stat(path: &str) -> Result<(FileType, FileMode, usize)> {
let filesystem = FILESYSTEM.lock();
if let Some(ref fs) = *filesystem {
fs.stat(path)
} else {
Err(crate::error::Error::NotInitialized)
}
}
/// File system statistics for diagnostics
#[derive(Debug, Clone)]
pub struct FileSystemStats {
pub files_count: usize,
pub directories_count: usize,
pub total_size: usize,
}
/// Get file system statistics for diagnostics
pub fn get_filesystem_stats() -> Result<FileSystemStats> {
let filesystem = FILESYSTEM.lock();
if let Some(ref fs) = *filesystem {
let mut files_count = 0;
let mut directories_count = 0;
let mut total_size = 0;
// Count files recursively (simplified implementation)
fn count_files(
file: &MemFile,
files: &mut usize,
dirs: &mut usize,
size: &mut usize,
) {
if file.is_dir() {
*dirs += 1;
for child in file.children.values() {
count_files(child, files, dirs, size);
}
} else {
*files += 1;
*size += file.data.len();
}
}
count_files(
&fs.root,
&mut files_count,
&mut directories_count,
&mut total_size,
);
Ok(FileSystemStats {
files_count,
directories_count,
total_size,
})
} else {
Err(crate::error::Error::NotInitialized)
}
}

Ver fichero

@@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0
//! Advanced memory allocator with debugging and tracking capabilities
use alloc::{collections::BTreeMap, vec::Vec};
use core::alloc::{GlobalAlloc, Layout};
use core::ptr::NonNull;
use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
use crate::error::{Error, Result};
use crate::sync::Spinlock;
/// Allocation tracking information
#[derive(Debug, Clone)]
pub struct AllocationInfo {
pub size: usize,
pub layout: Layout,
pub timestamp: u64,
pub caller: Option<usize>, // Return address for debugging
}
/// Memory allocation statistics
#[derive(Debug, Default)]
pub struct MemoryStats {
pub total_allocated: AtomicU64,
pub total_freed: AtomicU64,
pub current_allocated: AtomicU64,
pub allocation_count: AtomicU64,
pub free_count: AtomicU64,
pub peak_usage: AtomicU64,
pub fragmentation_events: AtomicU64,
}
/// Advanced allocator with tracking and debugging
pub struct AdvancedAllocator {
base_allocator: linked_list_allocator::LockedHeap,
allocations: Spinlock<BTreeMap<usize, AllocationInfo>>,
stats: MemoryStats,
debug_mode: AtomicU64, // Bitfield for debug features
}
impl AdvancedAllocator {
/// Create new advanced allocator
pub const fn new() -> Self {
Self {
base_allocator: linked_list_allocator::LockedHeap::empty(),
allocations: Spinlock::new(BTreeMap::new()),
stats: MemoryStats {
total_allocated: AtomicU64::new(0),
total_freed: AtomicU64::new(0),
current_allocated: AtomicU64::new(0),
allocation_count: AtomicU64::new(0),
free_count: AtomicU64::new(0),
peak_usage: AtomicU64::new(0),
fragmentation_events: AtomicU64::new(0),
},
debug_mode: AtomicU64::new(0),
}
}
/// Initialize the allocator with heap memory
pub unsafe fn init(&self, heap_start: usize, heap_size: usize) {
self.base_allocator
.lock()
.init(heap_start as *mut u8, heap_size);
}
/// Enable debug mode features
pub fn set_debug_mode(&self, mode: u64) {
self.debug_mode.store(mode, Ordering::Relaxed);
}
/// Get current memory statistics
pub fn get_stats(&self) -> MemoryStatsSnapshot {
MemoryStatsSnapshot {
total_allocated: self.stats.total_allocated.load(Ordering::Relaxed),
total_freed: self.stats.total_freed.load(Ordering::Relaxed),
current_allocated: self.stats.current_allocated.load(Ordering::Relaxed),
allocation_count: self.stats.allocation_count.load(Ordering::Relaxed),
free_count: self.stats.free_count.load(Ordering::Relaxed),
peak_usage: self.stats.peak_usage.load(Ordering::Relaxed),
fragmentation_events: self
.stats
.fragmentation_events
.load(Ordering::Relaxed),
active_allocations: self.allocations.lock().len(),
}
}
/// Get detailed allocation information
pub fn get_allocations(&self) -> Vec<(usize, AllocationInfo)> {
self.allocations
.lock()
.iter()
.map(|(&addr, info)| (addr, info.clone()))
.collect()
}
/// Check for memory leaks
pub fn check_leaks(&self) -> Vec<(usize, AllocationInfo)> {
let current_time = crate::time::get_jiffies();
self.allocations
.lock()
.iter()
.filter(|(_, info)| {
current_time.0 > info.timestamp
&& current_time.0 - info.timestamp > 10000
}) // Old allocations
.map(|(&addr, info)| (addr, info.clone()))
.collect()
}
/// Defragment memory (placeholder for future implementation)
pub fn defragment(&self) -> Result<usize> {
// This would implement memory compaction
// For now, just return that no bytes were moved
Ok(0)
}
}
unsafe impl GlobalAlloc for AdvancedAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let ptr = self.base_allocator.alloc(layout);
if !ptr.is_null() {
// Update statistics
let size = layout.size() as u64;
self.stats
.total_allocated
.fetch_add(size, Ordering::Relaxed);
self.stats.allocation_count.fetch_add(1, Ordering::Relaxed);
let current =
self.stats
.current_allocated
.fetch_add(size, Ordering::Relaxed) + size;
// Update peak usage
let mut peak = self.stats.peak_usage.load(Ordering::Relaxed);
while current > peak {
match self.stats.peak_usage.compare_exchange_weak(
peak,
current,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => break,
Err(x) => peak = x,
}
}
// Track allocation if debug mode is enabled
if self.debug_mode.load(Ordering::Relaxed) & 1 != 0 {
let info = AllocationInfo {
size: layout.size(),
layout,
timestamp: crate::time::get_jiffies().0,
caller: None, // TODO: Get return address
};
self.allocations.lock().insert(ptr as usize, info);
}
}
ptr
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.base_allocator.dealloc(ptr, layout);
if !ptr.is_null() {
// Update statistics
let size = layout.size() as u64;
self.stats.total_freed.fetch_add(size, Ordering::Relaxed);
self.stats.free_count.fetch_add(1, Ordering::Relaxed);
self.stats
.current_allocated
.fetch_sub(size, Ordering::Relaxed);
// Remove allocation tracking
if self.debug_mode.load(Ordering::Relaxed) & 1 != 0 {
self.allocations.lock().remove(&(ptr as usize));
}
}
}
}
/// Snapshot of memory statistics
#[derive(Debug, Clone)]
pub struct MemoryStatsSnapshot {
pub total_allocated: u64,
pub total_freed: u64,
pub current_allocated: u64,
pub allocation_count: u64,
pub free_count: u64,
pub peak_usage: u64,
pub fragmentation_events: u64,
pub active_allocations: usize,
}
/// Debug mode flags
pub mod debug_flags {
pub const TRACK_ALLOCATIONS: u64 = 1 << 0;
pub const DETECT_LEAKS: u64 = 1 << 1;
pub const POISON_MEMORY: u64 = 1 << 2;
pub const GUARD_PAGES: u64 = 1 << 3;
}
/// Global advanced allocator instance
#[global_allocator]
pub static ALLOCATOR: AdvancedAllocator = AdvancedAllocator::new();
/// Initialize the advanced allocator
pub unsafe fn init_advanced_allocator(heap_start: usize, heap_size: usize) {
ALLOCATOR.init(heap_start, heap_size);
ALLOCATOR.set_debug_mode(debug_flags::TRACK_ALLOCATIONS | debug_flags::DETECT_LEAKS);
crate::info!("Advanced allocator initialized with {} bytes", heap_size);
}
/// Get global memory statistics
pub fn get_memory_stats() -> MemoryStatsSnapshot {
ALLOCATOR.get_stats()
}
/// Get current allocations for debugging
pub fn get_current_allocations() -> Vec<(usize, AllocationInfo)> {
ALLOCATOR.get_allocations()
}
/// Check for memory leaks
pub fn check_memory_leaks() -> Vec<(usize, AllocationInfo)> {
ALLOCATOR.check_leaks()
}
/// Trigger memory defragmentation
pub fn defragment_memory() -> Result<usize> {
ALLOCATOR.defragment()
}

222
kernel/src/memory/allocator.rs Archivo normal
Ver fichero

@@ -0,0 +1,222 @@
// SPDX-License-Identifier: GPL-2.0
//! Memory allocator implementation - Enhanced with buddy allocator
use alloc::vec::Vec;
use crate::error::{Error, Result};
use crate::memory::advanced_allocator::ALLOCATOR;
use crate::sync::Spinlock;
use crate::types::{PhysAddr, VirtAddr, PAGE_SIZE};
/// Maximum order for buddy allocator (2^MAX_ORDER pages)
const MAX_ORDER: usize = 11;
/// Page frame number
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PageFrameNumber(pub usize);
impl PageFrameNumber {
pub fn to_phys_addr(self) -> PhysAddr {
PhysAddr::new(self.0 * PAGE_SIZE)
}
pub fn from_phys_addr(addr: PhysAddr) -> Self {
Self(addr.as_usize() / PAGE_SIZE)
}
}
/// Page allocation flags
#[derive(Debug, Clone, Copy)]
pub struct GfpFlags(pub u32);
impl GfpFlags {
pub const KERNEL: Self = Self(0x01);
pub const USER: Self = Self(0x02);
pub const ATOMIC: Self = Self(0x04);
pub const ZERO: Self = Self(0x08);
pub const DMA: Self = Self(0x10);
pub const HIGHMEM: Self = Self(0x20);
}
/// Free page block in buddy allocator
#[derive(Debug)]
struct FreeBlock {
pfn: PageFrameNumber,
#[allow(dead_code)]
order: usize,
}
/// Simple buddy allocator for page allocation
pub struct BuddyAllocator {
/// Free lists for each order
free_lists: [Vec<FreeBlock>; MAX_ORDER],
/// Total number of pages
total_pages: usize,
/// Base physical address
#[allow(dead_code)]
base_addr: PhysAddr,
}
impl BuddyAllocator {
pub fn new(base_addr: PhysAddr, total_pages: usize) -> Self {
const EMPTY_VEC: Vec<FreeBlock> = Vec::new();
Self {
free_lists: [EMPTY_VEC; MAX_ORDER],
total_pages,
base_addr,
}
}
/// Add a free memory region to the allocator
pub fn add_free_region(&mut self, start_pfn: PageFrameNumber, num_pages: usize) {
// Simple implementation: add as single-page blocks
for i in 0..num_pages {
self.free_lists[0].push(FreeBlock {
pfn: PageFrameNumber(start_pfn.0 + i),
order: 0,
});
}
}
/// Allocate pages of given order
pub fn alloc_pages(&mut self, order: usize) -> Result<PageFrameNumber> {
if order >= MAX_ORDER {
return Err(Error::InvalidArgument);
}
// Try to find a free block of the requested order
if let Some(block) = self.free_lists[order].pop() {
return Ok(block.pfn);
}
// For simplicity, just allocate from order 0 if we need higher orders
if order > 0 {
// Try to get multiple single pages (simplified approach)
let pages_needed = 1 << order;
if self.free_lists[0].len() >= pages_needed {
let first_pfn = self.free_lists[0].pop().unwrap().pfn;
// Remove additional pages
for _ in 1..pages_needed {
if self.free_lists[0].is_empty() {
// Put back the first page if we can't get enough
self.free_lists[0].push(FreeBlock {
pfn: first_pfn,
order: 0,
});
return Err(Error::OutOfMemory);
}
self.free_lists[0].pop();
}
return Ok(first_pfn);
}
}
Err(Error::OutOfMemory)
}
/// Free pages
pub fn free_pages(&mut self, pfn: PageFrameNumber, order: usize) {
if order >= MAX_ORDER {
return;
}
// Simple implementation: add back to the appropriate order
let pages_to_free = 1 << order;
for i in 0..pages_to_free {
self.free_lists[0].push(FreeBlock {
pfn: PageFrameNumber(pfn.0 + i),
order: 0,
});
}
}
/// Get free page count
pub fn free_pages_count(&self) -> usize {
let mut count = 0;
for order in 0..MAX_ORDER {
count += self.free_lists[order].len() * (1 << order);
}
count
}
}
/// Global buddy allocator for page allocation
static PAGE_ALLOCATOR: Spinlock<Option<BuddyAllocator>> = Spinlock::new(None);
/// Heap start address (will be set during initialization)
static mut HEAP_START: usize = 0;
static mut HEAP_SIZE: usize = 0;
/// Initialize the allocators
pub fn init() -> Result<()> {
// Initialize heap allocator
let heap_start = 0x_4444_4444_0000;
let heap_size = 100 * 1024; // 100 KB
unsafe {
HEAP_START = heap_start;
HEAP_SIZE = heap_size;
crate::memory::advanced_allocator::init_advanced_allocator(heap_start, heap_size);
}
// Initialize page allocator
// For demo purposes, assume we have 1024 pages starting at 1MB
let page_base = PhysAddr::new(0x100000); // 1MB
let total_pages = 1024;
let mut buddy = BuddyAllocator::new(page_base, total_pages);
buddy.add_free_region(
PageFrameNumber(page_base.as_usize() / PAGE_SIZE),
total_pages,
);
*PAGE_ALLOCATOR.lock() = Some(buddy);
Ok(())
}
/// Get heap statistics
pub fn heap_stats() -> (usize, usize) {
unsafe { (HEAP_START, HEAP_SIZE) }
}
/// Linux-compatible page allocation functions
pub fn alloc_pages(order: usize, flags: GfpFlags) -> Result<PageFrameNumber> {
let mut allocator = PAGE_ALLOCATOR.lock();
if let Some(ref mut alloc) = *allocator {
alloc.alloc_pages(order)
} else {
Err(Error::NotInitialized)
}
}
pub fn free_pages(pfn: PageFrameNumber, order: usize) {
let mut allocator = PAGE_ALLOCATOR.lock();
if let Some(ref mut alloc) = *allocator {
alloc.free_pages(pfn, order);
}
}
/// Allocate a single page
pub fn get_free_page(flags: GfpFlags) -> Result<VirtAddr> {
let pfn = alloc_pages(0, flags)?;
Ok(VirtAddr::new(pfn.to_phys_addr().as_usize()))
}
/// Free a single page
pub fn free_page(addr: VirtAddr) {
let pfn = PageFrameNumber::from_phys_addr(PhysAddr::new(addr.as_usize()));
free_pages(pfn, 0);
}
/// Get page allocator statistics
pub fn page_alloc_stats() -> Option<(usize, usize)> {
let allocator = PAGE_ALLOCATOR.lock();
if let Some(ref alloc) = *allocator {
Some((alloc.total_pages, alloc.free_pages_count()))
} else {
None
}
}

190
kernel/src/memory/kmalloc.rs Archivo normal
Ver fichero

@@ -0,0 +1,190 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel memory allocation (kmalloc)
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use core::ptr::NonNull;
use crate::error::{Error, Result};
use crate::memory::allocator::{alloc_pages, free_pages, GfpFlags, PageFrameNumber};
use crate::sync::Spinlock;
/// Kmalloc size classes (powers of 2)
const KMALLOC_SIZES: &[usize] = &[8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096];
const MAX_KMALLOC_SIZE: usize = 4096;
/// Slab allocator for small kernel allocations
/// Uses physical addresses directly - they're identity-mapped in the first 1GB
struct SlabAllocator {
size_classes: BTreeMap<usize, Vec<usize>>, // Store physical addresses
allocated_blocks: BTreeMap<usize, usize>, // Maps physical addresses to size classes
}
impl SlabAllocator {
const fn new() -> Self {
Self {
size_classes: BTreeMap::new(),
allocated_blocks: BTreeMap::new(),
}
}
fn allocate(&mut self, size: usize) -> Result<*mut u8> {
// Find appropriate size class
let size_class = KMALLOC_SIZES
.iter()
.find(|&&s| s >= size)
.copied()
.unwrap_or(MAX_KMALLOC_SIZE);
if size_class > MAX_KMALLOC_SIZE {
return Err(Error::OutOfMemory);
}
// Try to get from free list
if let Some(free_list) = self.size_classes.get_mut(&size_class) {
if let Some(addr) = free_list.pop() {
self.allocated_blocks.insert(addr, size_class);
return Ok(addr as *mut u8);
}
}
// Allocate new page and split it
self.allocate_new_slab(size_class)
}
fn allocate_new_slab(&mut self, size_class: usize) -> Result<*mut u8> {
// Allocate a page using buddy allocator
let pfn = alloc_pages(0, GfpFlags::KERNEL)?;
let page_addr = pfn.to_phys_addr().as_usize();
// Split page into blocks of size_class
let blocks_per_page = 4096 / size_class;
let free_list = self.size_classes.entry(size_class).or_insert_with(Vec::new);
for i in 1..blocks_per_page {
let block_addr = page_addr + (i * size_class);
free_list.push(block_addr);
}
// Return the first block
self.allocated_blocks.insert(page_addr, size_class);
Ok(page_addr as *mut u8)
}
fn deallocate(&mut self, ptr: *mut u8) -> Result<()> {
let addr = ptr as usize;
if let Some(size_class) = self.allocated_blocks.remove(&addr) {
let free_list =
self.size_classes.entry(size_class).or_insert_with(Vec::new);
free_list.push(addr);
Ok(())
} else {
Err(Error::InvalidArgument)
}
}
pub fn stats(&self) -> (usize, usize, usize) {
let mut allocated_count = 0;
let mut allocated_bytes = 0;
for (_, size_class) in &self.allocated_blocks {
allocated_count += 1;
allocated_bytes += size_class;
}
let mut free_count = 0;
for (_, free_list) in &self.size_classes {
free_count += free_list.len();
}
(allocated_count, allocated_bytes, free_count)
}
}
static SLAB_ALLOCATOR: Spinlock<SlabAllocator> = Spinlock::new(SlabAllocator::new());
/// Get kmalloc statistics
pub fn get_stats() -> (usize, usize, usize) {
let allocator = SLAB_ALLOCATOR.lock();
allocator.stats()
}
/// 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);
}
if size <= MAX_KMALLOC_SIZE {
// Use slab allocator for small allocations
let mut allocator = SLAB_ALLOCATOR.lock();
allocator.allocate(size)
} else {
// Use buddy allocator for large allocations
let pages_needed = (size + 4095) / 4096;
let order = pages_needed.next_power_of_two().trailing_zeros() as usize;
let pfn = alloc_pages(order, GfpFlags::KERNEL)?;
Ok(pfn.to_phys_addr().as_usize() as *mut u8)
}
}
/// Free kernel memory
pub fn kfree(ptr: *mut u8) {
if ptr.is_null() {
return;
}
// Try slab allocator first
if let Ok(()) = SLAB_ALLOCATOR.lock().deallocate(ptr) {
return;
}
// Try buddy allocator for large allocations
// TODO: Keep track of large allocations to know how many pages to free
// For now, assume single page
if let Some(_page) = NonNull::new(ptr as *mut crate::memory::Page) {
let pfn =
PageFrameNumber::from_phys_addr(crate::types::PhysAddr::new(ptr as usize));
free_pages(pfn, 0);
}
}
/// Allocate zeroed kernel memory
pub fn kzalloc(size: usize) -> Result<*mut u8> {
let ptr = kmalloc(size)?;
unsafe {
core::ptr::write_bytes(ptr, 0, size);
}
Ok(ptr)
}
/// Reallocate kernel memory
pub fn krealloc(ptr: *mut u8, old_size: usize, new_size: usize) -> Result<*mut u8> {
if ptr.is_null() {
return kmalloc(new_size);
}
if new_size == 0 {
kfree(ptr);
return Ok(core::ptr::null_mut());
}
let new_ptr = kmalloc(new_size)?;
let copy_size = core::cmp::min(old_size, new_size);
unsafe {
core::ptr::copy_nonoverlapping(ptr, new_ptr, copy_size);
}
kfree(ptr);
Ok(new_ptr)
}
/// Initialize the slab allocator
pub fn init() -> Result<()> {
// No initialization needed - we use physical addresses directly
Ok(())
}

622
kernel/src/memory/mod.rs Archivo normal
Ver fichero

@@ -0,0 +1,622 @@
// SPDX-License-Identifier: GPL-2.0
//! Memory management subsystem
pub mod advanced_allocator;
pub mod allocator;
pub mod kmalloc;
pub mod page;
pub mod page_table;
pub mod vmalloc;
// Re-export important types
use alloc::string::String;
use linked_list_allocator::LockedHeap;
pub use page::Page;
use crate::error::{Error, Result};
pub use crate::types::{Pfn, PhysAddr, VirtAddr}; // Re-export from types
/// GFP (Get Free Pages) flags - compatible with Linux kernel
pub mod gfp {
pub const GFP_KERNEL: u32 = 0;
pub const GFP_ATOMIC: u32 = 1;
pub const GFP_USER: u32 = 2;
pub const GFP_HIGHUSER: u32 = 3;
pub const GFP_DMA: u32 = 4;
pub const GFP_DMA32: u32 = 8;
pub const GFP_NOWAIT: u32 = 16;
pub const GFP_NOIO: u32 = 32;
pub const GFP_NOFS: u32 = 64;
pub const GFP_ZERO: u32 = 128;
}
/// Global heap allocator (using advanced allocator)
// #[global_allocator]
// static ALLOCATOR: LockedHeap = LockedHeap::empty();
/// Linux-compatible allocation flags
#[derive(Clone, Copy, PartialEq)]
pub struct AllocFlags(u32);
impl AllocFlags {
pub const fn new(flags: u32) -> Self {
Self(flags)
}
pub fn as_raw(self) -> u32 {
self.0
}
pub fn contains(self, flags: AllocFlags) -> bool {
(self.0 & flags.0) == flags.0
}
}
/// GFP flags constants
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()?;
page::init()?;
// Initialize zone allocator
init_zones()?;
// Set up buddy allocator
init_buddy_allocator()?;
// Initialize slab allocator
init_slab_allocator()?;
crate::info!("Memory management initialized");
Ok(())
}
/// Initialize memory zones (DMA, Normal, High)
fn init_zones() -> Result<()> {
// TODO: Set up memory zones based on architecture
Ok(())
}
/// Initialize buddy allocator for page allocation
fn init_buddy_allocator() -> Result<()> {
// TODO: Set up buddy allocator
Ok(())
}
/// Initialize slab allocator for object caching
fn init_slab_allocator() -> Result<()> {
// TODO: Set up SLAB/SLUB allocator
Ok(())
}
/// Physical memory information
#[derive(Debug)]
pub struct MemoryInfo {
pub total_pages: usize,
pub free_pages: usize,
pub used_pages: usize,
pub kernel_pages: usize,
}
/// Get current memory information
pub fn memory_info() -> MemoryInfo {
MemoryInfo {
total_pages: 0, // TODO: implement
free_pages: 0,
used_pages: 0,
kernel_pages: 0,
}
}
/// 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()
}
/// Free a page of physical memory
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, 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
Ok(())
}
/// Convert virtual address to physical address
pub fn virt_to_phys(virt: VirtAddr) -> Result<PhysAddr> {
// TODO: implement address translation
Ok(PhysAddr::new(virt.as_usize()))
}
/// Convert physical address to virtual address
pub fn phys_to_virt(phys: PhysAddr) -> Result<VirtAddr> {
// TODO: implement address translation
Ok(VirtAddr::new(phys.as_usize()))
}
/// Page table entry
#[derive(Debug, Clone, Copy)]
pub struct PageTableEntry(pub u64);
impl PageTableEntry {
pub const fn new() -> Self {
Self(0)
}
pub fn present(self) -> bool {
self.0 & 1 != 0
}
pub fn writable(self) -> bool {
self.0 & 2 != 0
}
pub fn user_accessible(self) -> bool {
self.0 & 4 != 0
}
pub fn frame(self) -> Pfn {
Pfn((self.0 >> 12) as usize)
}
pub fn set_present(&mut self, present: bool) {
if present {
self.0 |= 1;
} else {
self.0 &= !1;
}
}
pub fn set_writable(&mut self, writable: bool) {
if writable {
self.0 |= 2;
} else {
self.0 &= !2;
}
}
pub fn set_user_accessible(&mut self, user: bool) {
if user {
self.0 |= 4;
} else {
self.0 &= !4;
}
}
pub fn set_frame(&mut self, frame: Pfn) {
self.0 = (self.0 & 0xfff) | ((frame.0 as u64) << 12);
}
}
/// Page table
#[repr(align(4096))]
pub struct PageTable {
entries: [PageTableEntry; 512],
}
impl PageTable {
pub const fn new() -> Self {
Self {
entries: [PageTableEntry::new(); 512],
}
}
pub fn zero(&mut self) {
for entry in self.entries.iter_mut() {
*entry = PageTableEntry::new();
}
}
}
/// Memory mapping flags
bitflags::bitflags! {
pub struct MapFlags: u32 {
const READ = 1 << 0;
const WRITE = 1 << 1;
const EXECUTE = 1 << 2;
const USER = 1 << 3;
const GLOBAL = 1 << 4;
const CACHED = 1 << 5;
const DEVICE = 1 << 6;
}
}
/// User space pointer wrapper for safe kernel-user space data transfer
#[derive(Debug, Clone, Copy)]
pub struct UserPtr<T> {
ptr: *mut T,
}
impl<T> UserPtr<T> {
/// Create a new UserPtr with validation
pub fn new(ptr: *mut T) -> Result<Self> {
if ptr.is_null() {
return Err(Error::InvalidArgument);
}
// TODO: Add proper user space validation
Ok(Self { ptr })
}
/// Create a new UserPtr from const pointer
pub fn from_const(ptr: *const T) -> Result<Self> {
Self::new(ptr as *mut T)
}
/// Get the raw pointer
pub fn as_ptr(&self) -> *mut T {
self.ptr
}
/// Cast to different type
pub fn cast<U>(&self) -> UserPtr<U> {
UserPtr {
ptr: self.ptr as *mut U,
}
}
/// Check if the pointer is null
pub fn is_null(&self) -> bool {
self.ptr.is_null()
}
/// Write data to user space
pub fn write(&self, data: T) -> Result<()> {
// TODO: Implement proper user space access validation
// For now, this is a stub
if self.ptr.is_null() {
return Err(Error::InvalidArgument);
}
// In a real kernel, this would use copy_to_user or similar
// For now, we'll use unsafe direct write (this is NOT safe for real use)
unsafe {
core::ptr::write(self.ptr, data);
}
Ok(())
}
}
/// User space slice pointer for array-like data
#[derive(Debug, Clone, Copy)]
pub struct UserSlicePtr {
ptr: *mut u8,
len: usize,
}
impl UserSlicePtr {
/// Create a new UserSlicePtr (unsafe as it's not validated)
pub unsafe fn new(ptr: *mut u8, len: usize) -> Self {
Self { ptr, len }
}
/// Get the raw pointer
pub fn as_ptr(&self) -> *mut u8 {
self.ptr
}
/// Get the length
pub fn len(&self) -> usize {
self.len
}
/// Check if empty
pub fn is_empty(&self) -> bool {
self.len == 0
}
/// Copy data from a slice to user space
pub fn copy_from_slice(&self, data: &[u8]) -> Result<()> {
// TODO: Implement proper user space access validation
// For now, this is a stub
if self.ptr.is_null() {
return Err(Error::InvalidArgument);
}
let copy_len = core::cmp::min(self.len, data.len());
// In a real kernel, this would use copy_to_user or similar
// For now, we'll use unsafe direct copy (this is NOT safe for real use)
unsafe {
core::ptr::copy_nonoverlapping(data.as_ptr(), self.ptr, copy_len);
}
Ok(())
}
/// Copy data from user space to a slice
pub fn copy_to_slice(&self, data: &mut [u8]) -> Result<()> {
// TODO: Implement proper user space access validation
// For now, this is a stub
if self.ptr.is_null() {
return Err(Error::InvalidArgument);
}
let copy_len = core::cmp::min(self.len, data.len());
// In a real kernel, this would use copy_from_user or similar
// For now, we'll use unsafe direct copy (this is NOT safe for real use)
unsafe {
core::ptr::copy_nonoverlapping(self.ptr, data.as_mut_ptr(), copy_len);
}
Ok(())
}
}
/// Copy data to user space
pub fn copy_to_user(user_ptr: UserPtr<u8>, data: &[u8]) -> Result<()> {
// TODO: Implement proper user space access validation
// This should check if the user pointer is valid and accessible
if user_ptr.ptr.is_null() {
return Err(Error::InvalidArgument);
}
// In a real kernel, this would use proper copy_to_user with page fault handling
// For now, we'll use unsafe direct copy (NOT safe for real use)
unsafe {
core::ptr::copy_nonoverlapping(data.as_ptr(), user_ptr.ptr, data.len());
}
Ok(())
}
/// Copy data from user space
pub fn copy_from_user(data: &mut [u8], user_ptr: UserPtr<u8>) -> Result<()> {
// TODO: Implement proper user space access validation
// This should check if the user pointer is valid and accessible
if user_ptr.ptr.is_null() {
return Err(Error::InvalidArgument);
}
// In a real kernel, this would use proper copy_from_user with page fault
// handling For now, we'll use unsafe direct copy (NOT safe for real use)
unsafe {
core::ptr::copy_nonoverlapping(user_ptr.ptr, data.as_mut_ptr(), data.len());
}
Ok(())
}
/// Copy a string from user space
pub fn copy_string_from_user(user_ptr: UserPtr<u8>, max_len: usize) -> Result<String> {
// TODO: Implement proper user space access validation
if user_ptr.ptr.is_null() {
return Err(Error::InvalidArgument);
}
let mut buffer = alloc::vec![0u8; max_len];
let mut len = 0;
// Copy byte by byte until null terminator or max length
unsafe {
for i in 0..max_len {
let byte = *user_ptr.ptr.add(i);
if byte == 0 {
break;
}
buffer[i] = byte;
len += 1;
}
}
buffer.truncate(len);
String::from_utf8(buffer).map_err(|_| Error::InvalidArgument)
}
/// Memory mapping area structure
#[derive(Debug, Clone)]
pub struct VmaArea {
pub vm_start: VirtAddr,
pub vm_end: VirtAddr,
pub vm_prot: u32,
pub vm_flags: u32,
}
impl VmaArea {
pub fn new(start: VirtAddr, end: VirtAddr, prot: u32) -> Self {
Self {
vm_start: start,
vm_end: end,
vm_prot: prot,
vm_flags: 0,
}
}
}
/// Allocate virtual memory for mmap
pub fn allocate_virtual_memory(size: u64, prot: u32, flags: u32) -> Result<VmaArea> {
use crate::memory::kmalloc::kmalloc;
// Allocate physical pages first
let pages_needed = (size + 4095) / 4096;
let phys_addr = kmalloc(size as usize)?;
// Find a free virtual address range
let virt_addr = find_free_virtual_range(size)?;
// Map the pages (simplified implementation)
map_pages(virt_addr, PhysAddr::new(phys_addr as usize), size, prot)?;
Ok(VmaArea::new(
virt_addr,
VirtAddr::new(virt_addr.as_usize() + size as usize),
prot,
))
}
/// Free virtual memory
pub fn free_virtual_memory(addr: VirtAddr, size: u64) -> Result<()> {
// Unmap pages
unmap_pages(addr, size)?;
// Free physical memory (simplified)
crate::memory::kmalloc::kfree(addr.as_usize() as *mut u8);
Ok(())
}
/// Find a free virtual address range
fn find_free_virtual_range(size: u64) -> Result<VirtAddr> {
// Simplified implementation - start from user space
const USER_SPACE_START: usize = 0x400000; // 4MB
const USER_SPACE_END: usize = 0x80000000; // 2GB
let mut addr = USER_SPACE_START;
while addr + size as usize <= USER_SPACE_END {
// Check if range is free (simplified check)
if is_virtual_range_free(VirtAddr::new(addr), size) {
return Ok(VirtAddr::new(addr));
}
addr += 4096; // Page size
}
Err(Error::ENOMEM)
}
/// Check if virtual range is free
pub fn is_virtual_range_free(_addr: VirtAddr, _size: u64) -> bool {
// Simplified implementation - assume it's free
// In a real implementation, this would check page tables
true
}
/// Map virtual pages to physical pages
fn map_pages(virt: VirtAddr, phys: PhysAddr, size: u64, _prot: u32) -> Result<()> {
// Simplified page mapping
// In a real implementation, this would set up page table entries
crate::info!(
"Mapping virtual 0x{:x} to physical 0x{:x}, size: {}",
virt.as_usize(),
phys.as_usize(),
size
);
Ok(())
}
/// Unmap virtual pages
fn unmap_pages(virt: VirtAddr, size: u64) -> Result<()> {
// Simplified page unmapping
crate::info!("Unmapping virtual 0x{:x}, size: {}", virt.as_usize(), size);
Ok(())
}
/// Heap management for brk syscall
static mut HEAP_START: VirtAddr = VirtAddr::new(0);
static mut HEAP_END: VirtAddr = VirtAddr::new(0);
/// Get current heap end
pub fn get_heap_end() -> VirtAddr {
unsafe { HEAP_END }
}
/// Set heap end
pub fn set_heap_end(new_end: VirtAddr) -> Result<()> {
unsafe {
if HEAP_START.as_usize() == 0 {
// Initialize heap
HEAP_START = VirtAddr::new(0x10000000); // 256MB
HEAP_END = HEAP_START;
}
if new_end >= HEAP_START {
HEAP_END = new_end;
Ok(())
} else {
Err(Error::EINVAL)
}
}
}
/// Initialize heap management
pub fn init_heap() -> Result<()> {
unsafe {
HEAP_START = VirtAddr::new(0x10000000); // 256MB
HEAP_END = HEAP_START;
}
Ok(())
}

233
kernel/src/memory/page.rs Archivo normal
Ver fichero

@@ -0,0 +1,233 @@
// SPDX-License-Identifier: GPL-2.0
//! Page frame allocator
use core::sync::atomic::{AtomicU32, Ordering};
use crate::error::{Error, Result};
use crate::sync::Spinlock;
use crate::types::{Pfn, PhysAddr};
/// Page structure - similar to Linux struct page
#[derive(Debug)]
pub struct Page {
/// Page frame number
pub pfn: Pfn,
/// Page flags
pub flags: AtomicU32,
/// Reference count
pub count: AtomicU32,
/// Virtual address if mapped
pub virtual_addr: Option<crate::types::VirtAddr>,
}
impl Page {
/// Create a new page
pub fn new(pfn: Pfn) -> Self {
Self {
pfn,
flags: AtomicU32::new(0),
count: AtomicU32::new(1),
virtual_addr: None,
}
}
/// Get physical address
pub fn phys_addr(&self) -> PhysAddr {
PhysAddr(self.pfn.0 * 4096) // Assuming 4KB pages
}
/// Get page flags
pub fn flags(&self) -> u32 {
self.flags.load(Ordering::Relaxed)
}
/// Set page flags
pub fn set_flags(&self, flags: u32) {
self.flags.store(flags, Ordering::Relaxed);
}
/// Get reference count
pub fn count(&self) -> u32 {
self.count.load(Ordering::Relaxed)
}
/// Increment reference count
pub fn get(&self) -> u32 {
self.count.fetch_add(1, Ordering::Relaxed) + 1
}
/// Decrement reference count
pub fn put(&self) -> u32 {
let old_count = self.count.fetch_sub(1, Ordering::Relaxed);
if old_count == 1 {
// Last reference - page can be freed
// TODO: Add to free list
}
old_count - 1
}
}
/// Page flags (Linux compatible)
pub mod page_flags {
pub const PG_LOCKED: u32 = 0;
pub const PG_ERROR: u32 = 1;
pub const PG_REFERENCED: u32 = 2;
pub const PG_UPTODATE: u32 = 3;
pub const PG_DIRTY: u32 = 4;
pub const PG_LRU: u32 = 5;
pub const PG_ACTIVE: u32 = 6;
pub const PG_SLAB: u32 = 7;
pub const PG_OWNER_PRIV_1: u32 = 8;
pub const PG_ARCH_1: u32 = 9;
pub const PG_RESERVED: u32 = 10;
pub const PG_PRIVATE: u32 = 11;
pub const PG_PRIVATE_2: u32 = 12;
pub const PG_WRITEBACK: u32 = 13;
pub const PG_HEAD: u32 = 14;
pub const PG_SWAPCACHE: u32 = 15;
pub const PG_MAPPEDTODISK: u32 = 16;
pub const PG_RECLAIM: u32 = 17;
pub const PG_SWAPBACKED: u32 = 18;
pub const PG_UNEVICTABLE: u32 = 19;
}
/// Page frame allocator
pub static PAGE_ALLOCATOR: Spinlock<PageAllocator> = Spinlock::new(PageAllocator::new());
/// Page allocator implementation
pub struct PageAllocator {
free_list_head: Option<PhysAddr>,
total_pages: usize,
allocated_pages: usize,
free_count: usize,
}
impl PageAllocator {
pub const fn new() -> Self {
Self {
free_list_head: None,
total_pages: 0,
allocated_pages: 0,
free_count: 0,
}
}
/// Add a range of pages to the free list
pub fn add_free_range(&mut self, start: Pfn, count: usize) {
// Safety: Only add pages that are within the identity-mapped region (0-1GB)
// Boot assembly maps 0-1GB with 2MB pages
const MAX_IDENTITY_MAPPED_PFN: usize = (1024 * 1024 * 1024) / 4096; // 1GB / 4KB
let safe_count = if start.0 >= MAX_IDENTITY_MAPPED_PFN {
// Start is beyond identity mapping, skip entirely
return;
} else if start.0 + count > MAX_IDENTITY_MAPPED_PFN {
// Trim to stay within identity mapping
MAX_IDENTITY_MAPPED_PFN - start.0
} else {
count
};
for i in 0..safe_count {
let pfn = Pfn(start.0 + i);
let phys_addr = PhysAddr(pfn.0 * 4096);
// Store current head in the new page
// We can write to phys_addr because it's identity mapped
unsafe {
let ptr = phys_addr.0 as *mut u64;
*ptr = self.free_list_head.map(|a| a.0 as u64).unwrap_or(0);
}
// Update head
self.free_list_head = Some(phys_addr);
}
self.total_pages += safe_count;
self.free_count += safe_count;
}
/// Allocate a single page
fn alloc_page(&mut self) -> Result<Pfn> {
if let Some(head_addr) = self.free_list_head {
// Read next ptr from head
let next_addr_u64 = unsafe { *(head_addr.0 as *const u64) };
self.free_list_head = if next_addr_u64 == 0 {
None
} else {
Some(PhysAddr(next_addr_u64 as usize))
};
self.allocated_pages += 1;
self.free_count -= 1;
Ok(Pfn(head_addr.0 / 4096))
} else {
Err(Error::OutOfMemory)
}
}
/// Free a single page
fn free_page(&mut self, pfn: Pfn) {
let phys_addr = PhysAddr(pfn.0 * 4096);
unsafe {
let ptr = phys_addr.0 as *mut u64;
*ptr = self.free_list_head.map(|a| a.0 as u64).unwrap_or(0);
}
self.free_list_head = Some(phys_addr);
self.allocated_pages -= 1;
self.free_count += 1;
}
/// Get statistics
fn stats(&self) -> (usize, usize, usize) {
(self.total_pages, self.allocated_pages, self.free_count)
}
}
/// Initialize the page allocator
pub fn init() -> Result<()> {
// Page allocator stub - no actual pages initialized yet
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();
let pfn = allocator.alloc_page()?;
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);
let mut allocator = PAGE_ALLOCATOR.lock();
allocator.free_page(pfn);
}
/// Get page allocator statistics
pub fn stats() -> (usize, usize, usize) {
let allocator = PAGE_ALLOCATOR.lock();
allocator.stats()
}

273
kernel/src/memory/page_table.rs Archivo normal
Ver fichero

@@ -0,0 +1,273 @@
// SPDX-License-Identifier: GPL-2.0
//! Page table management for x86_64
use core::arch::asm;
use crate::error::{Error, Result};
use crate::memory::allocator::{alloc_pages, free_pages, GfpFlags, PageFrameNumber};
use crate::types::{PhysAddr, VirtAddr, PAGE_SIZE};
/// Page table entry flags
#[derive(Debug, Clone, Copy)]
pub struct PageTableFlags(pub u64);
impl PageTableFlags {
pub const PRESENT: Self = Self(1 << 0);
pub const WRITABLE: Self = Self(1 << 1);
pub const USER_ACCESSIBLE: Self = Self(1 << 2);
pub const WRITE_THROUGH: Self = Self(1 << 3);
pub const NO_CACHE: Self = Self(1 << 4);
pub const ACCESSED: Self = Self(1 << 5);
pub const DIRTY: Self = Self(1 << 6);
pub const HUGE_PAGE: Self = Self(1 << 7);
pub const GLOBAL: Self = Self(1 << 8);
pub const NO_EXECUTE: Self = Self(1 << 63);
pub fn empty() -> Self {
Self(0)
}
pub fn kernel_page() -> Self {
Self::PRESENT | Self::WRITABLE
}
pub fn user_page() -> Self {
Self::PRESENT | Self::WRITABLE | Self::USER_ACCESSIBLE
}
pub fn contains(self, flag: Self) -> bool {
self.0 & flag.0 != 0
}
}
impl core::ops::BitOr for PageTableFlags {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl core::ops::BitOrAssign for PageTableFlags {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
/// Page table entry
#[repr(transparent)]
#[derive(Debug, Clone, Copy)]
pub struct PageTableEntry(pub u64);
impl PageTableEntry {
pub fn new() -> Self {
Self(0)
}
pub fn is_present(self) -> bool {
self.0 & 1 != 0
}
pub fn set_frame(self, frame: PageFrameNumber, flags: PageTableFlags) -> Self {
let addr = frame.to_phys_addr().as_usize() as u64;
Self((addr & !0xfff) | flags.0)
}
pub fn frame(self) -> Option<PageFrameNumber> {
if self.is_present() {
Some(PageFrameNumber::from_phys_addr(PhysAddr::new(
(self.0 & !0xfff) as usize,
)))
} else {
None
}
}
pub fn flags(self) -> PageTableFlags {
PageTableFlags(self.0 & 0xfff)
}
}
/// Page table with 512 entries (x86_64)
#[repr(align(4096))]
pub struct PageTable {
entries: [PageTableEntry; 512],
}
impl PageTable {
pub fn new() -> Self {
Self {
entries: [PageTableEntry::new(); 512],
}
}
pub fn zero(&mut self) {
for entry in &mut self.entries {
*entry = PageTableEntry::new();
}
}
pub fn entry(&mut self, index: usize) -> &mut PageTableEntry {
&mut self.entries[index]
}
pub fn entry_ref(&self, index: usize) -> &PageTableEntry {
&self.entries[index]
}
}
/// Page table manager
pub struct PageTableManager {
root_table: PhysAddr,
}
impl PageTableManager {
pub fn new() -> Result<Self> {
// Allocate a page for the root page table (PML4)
let pfn = alloc_pages(0, GfpFlags::KERNEL)?;
let root_table = pfn.to_phys_addr();
// Zero the root table
unsafe {
let table = root_table.as_usize() as *mut PageTable;
(*table).zero();
}
Ok(Self { root_table })
}
pub fn root_table_addr(&self) -> PhysAddr {
self.root_table
}
/// Map a virtual page to a physical page
pub fn map_page(
&mut self,
virt_addr: VirtAddr,
phys_addr: PhysAddr,
flags: PageTableFlags,
) -> Result<()> {
let virt_page = virt_addr.as_usize() / PAGE_SIZE;
let pfn = PageFrameNumber::from_phys_addr(phys_addr);
// Extract page table indices from virtual address
let pml4_index = (virt_page >> 27) & 0x1ff;
let pdp_index = (virt_page >> 18) & 0x1ff;
let pd_index = (virt_page >> 9) & 0x1ff;
let pt_index = virt_page & 0x1ff;
// Walk and create page tables as needed
let pml4 = unsafe { &mut *(self.root_table.as_usize() as *mut PageTable) };
// Get or create PDP
let pdp_addr = if pml4.entry_ref(pml4_index).is_present() {
pml4.entry_ref(pml4_index).frame().unwrap().to_phys_addr()
} else {
let pdp_pfn = alloc_pages(0, GfpFlags::KERNEL)?;
let pdp_addr = pdp_pfn.to_phys_addr();
unsafe {
let pdp_table = pdp_addr.as_usize() as *mut PageTable;
(*pdp_table).zero();
}
*pml4.entry(pml4_index) = PageTableEntry::new()
.set_frame(pdp_pfn, PageTableFlags::kernel_page());
pdp_addr
};
// Get or create PD
let pdp = unsafe { &mut *(pdp_addr.as_usize() as *mut PageTable) };
let pd_addr = if pdp.entry_ref(pdp_index).is_present() {
pdp.entry_ref(pdp_index).frame().unwrap().to_phys_addr()
} else {
let pd_pfn = alloc_pages(0, GfpFlags::KERNEL)?;
let pd_addr = pd_pfn.to_phys_addr();
unsafe {
let pd_table = pd_addr.as_usize() as *mut PageTable;
(*pd_table).zero();
}
*pdp.entry(pdp_index) = PageTableEntry::new()
.set_frame(pd_pfn, PageTableFlags::kernel_page());
pd_addr
};
// Get or create PT
let pd = unsafe { &mut *(pd_addr.as_usize() as *mut PageTable) };
let pt_addr = if pd.entry_ref(pd_index).is_present() {
pd.entry_ref(pd_index).frame().unwrap().to_phys_addr()
} else {
let pt_pfn = alloc_pages(0, GfpFlags::KERNEL)?;
let pt_addr = pt_pfn.to_phys_addr();
unsafe {
let pt_table = pt_addr.as_usize() as *mut PageTable;
(*pt_table).zero();
}
*pd.entry(pd_index) = PageTableEntry::new()
.set_frame(pt_pfn, PageTableFlags::kernel_page());
pt_addr
};
// Set the final page mapping
let pt = unsafe { &mut *(pt_addr.as_usize() as *mut PageTable) };
*pt.entry(pt_index) = PageTableEntry::new().set_frame(pfn, flags);
// Flush TLB for this page
unsafe {
asm!("invlpg [{}]", in(reg) virt_addr.as_usize(), options(nostack, preserves_flags));
}
Ok(())
}
/// Unmap a virtual page
pub fn unmap_page(&mut self, virt_addr: VirtAddr) -> Result<()> {
let virt_page = virt_addr.as_usize() / PAGE_SIZE;
// Extract page table indices
let pml4_index = (virt_page >> 27) & 0x1ff;
let pdp_index = (virt_page >> 18) & 0x1ff;
let pd_index = (virt_page >> 9) & 0x1ff;
let pt_index = virt_page & 0x1ff;
// Walk page tables
let pml4 = unsafe { &mut *(self.root_table.as_usize() as *mut PageTable) };
if !pml4.entry_ref(pml4_index).is_present() {
return Err(Error::InvalidArgument);
}
let pdp_addr = pml4.entry_ref(pml4_index).frame().unwrap().to_phys_addr();
let pdp = unsafe { &mut *(pdp_addr.as_usize() as *mut PageTable) };
if !pdp.entry_ref(pdp_index).is_present() {
return Err(Error::InvalidArgument);
}
let pd_addr = pdp.entry_ref(pdp_index).frame().unwrap().to_phys_addr();
let pd = unsafe { &mut *(pd_addr.as_usize() as *mut PageTable) };
if !pd.entry_ref(pd_index).is_present() {
return Err(Error::InvalidArgument);
}
let pt_addr = pd.entry_ref(pd_index).frame().unwrap().to_phys_addr();
let pt = unsafe { &mut *(pt_addr.as_usize() as *mut PageTable) };
// Clear the page table entry
*pt.entry(pt_index) = PageTableEntry::new();
// Flush TLB for this page
unsafe {
asm!("invlpg [{}]", in(reg) virt_addr.as_usize(), options(nostack, preserves_flags));
}
Ok(())
}
/// Switch to this page table
pub fn switch_to(&self) {
unsafe {
asm!("mov cr3, {}", in(reg) self.root_table.as_usize(), options(nostack, preserves_flags));
}
}
}

243
kernel/src/memory/vmalloc.rs Archivo normal
Ver fichero

@@ -0,0 +1,243 @@
// SPDX-License-Identifier: GPL-2.0
//! Virtual memory allocation
use alloc::collections::BTreeMap;
use core::ptr::NonNull;
use crate::error::{Error, Result};
use crate::memory::allocator::{alloc_pages, free_pages, GfpFlags, PageFrameNumber};
use crate::memory::page_table::{PageTableFlags, PageTableManager};
use crate::sync::Spinlock;
use crate::types::{PhysAddr, VirtAddr};
/// Virtual memory area descriptor
#[derive(Debug, Clone)]
struct VmallocArea {
start: VirtAddr,
end: VirtAddr,
size: usize,
pages: alloc::vec::Vec<PhysAddr>,
}
/// Vmalloc allocator
struct VmallocAllocator {
areas: BTreeMap<usize, VmallocArea>,
next_addr: usize,
page_table: Option<PageTableManager>,
}
impl VmallocAllocator {
const fn new() -> Self {
Self {
areas: BTreeMap::new(),
next_addr: 0xFFFF_8000_0000_0000, // Kernel vmalloc area start
page_table: None,
}
}
fn init(&mut self) -> Result<()> {
self.page_table = Some(PageTableManager::new()?);
Ok(())
}
fn allocate(&mut self, size: usize) -> Result<VirtAddr> {
if size == 0 {
return Err(Error::InvalidArgument);
}
// Align size to page boundary
let aligned_size = (size + 4095) & !4095;
let pages_needed = aligned_size / 4096;
// Find virtual address space
let start_addr = self.find_free_area(aligned_size)?;
let end_addr = start_addr + aligned_size;
// Allocate physical pages
let mut pages = alloc::vec::Vec::new();
for _ in 0..pages_needed {
let pfn = alloc_pages(0, GfpFlags::KERNEL)?;
pages.push(pfn.to_phys_addr());
}
// Map virtual to physical pages
if let Some(ref mut page_table) = self.page_table {
for (i, &phys_addr) in pages.iter().enumerate() {
let virt_addr = VirtAddr::new(start_addr + i * 4096);
page_table.map_page(
virt_addr,
phys_addr,
PageTableFlags::kernel_page(),
)?;
}
}
let area = VmallocArea {
start: VirtAddr::new(start_addr),
end: VirtAddr::new(end_addr),
size: aligned_size,
pages,
};
self.areas.insert(start_addr, area);
Ok(VirtAddr::new(start_addr))
}
fn deallocate(&mut self, addr: VirtAddr) -> Result<()> {
let addr_usize = addr.as_usize();
if let Some(area) = self.areas.remove(&addr_usize) {
// Unmap pages from page tables
if let Some(ref mut page_table) = self.page_table {
for i in 0..(area.size / 4096) {
let virt_addr =
VirtAddr::new(area.start.as_usize() + i * 4096);
let _ = page_table.unmap_page(virt_addr);
}
}
// Free physical pages
for phys_addr in area.pages {
if let Some(_page_ptr) = NonNull::new(
phys_addr.as_usize() as *mut crate::memory::Page
) {
let pfn = PageFrameNumber::from_phys_addr(phys_addr);
free_pages(pfn, 0);
}
}
Ok(())
} else {
Err(Error::InvalidArgument)
}
}
fn find_free_area(&mut self, size: usize) -> Result<usize> {
// Simple linear search for free area
// In a real implementation, this would be more sophisticated
let mut addr = self.next_addr;
// Check if area is free
for (start, area) in &self.areas {
if addr >= *start && addr < area.end.as_usize() {
addr = area.end.as_usize();
}
}
self.next_addr = addr + size;
Ok(addr)
}
pub fn stats(&self) -> (usize, usize) {
let mut allocated_bytes = 0;
for (_, area) in &self.areas {
allocated_bytes += area.size;
}
(self.areas.len(), allocated_bytes)
}
}
static VMALLOC_ALLOCATOR: Spinlock<VmallocAllocator> = Spinlock::new(VmallocAllocator::new());
/// Get vmalloc statistics
pub fn get_stats() -> (usize, usize) {
let allocator = VMALLOC_ALLOCATOR.lock();
allocator.stats()
}
/// Allocate virtual memory
pub fn vmalloc(size: usize) -> Result<VirtAddr> {
let mut allocator = VMALLOC_ALLOCATOR.lock();
allocator.allocate(size)
}
/// Free virtual memory
pub fn vfree(addr: VirtAddr) {
let mut allocator = VMALLOC_ALLOCATOR.lock();
let _ = allocator.deallocate(addr);
}
/// Allocate zeroed virtual memory
pub fn vzalloc(size: usize) -> Result<VirtAddr> {
let addr = vmalloc(size)?;
// Zero the memory
unsafe {
core::ptr::write_bytes(addr.as_usize() as *mut u8, 0, size);
}
Ok(addr)
}
/// Map physical memory into virtual space
pub fn vmap_phys(phys_addr: PhysAddr, size: usize) -> Result<VirtAddr> {
let start_addr;
let aligned_size;
{
let mut allocator = VMALLOC_ALLOCATOR.lock();
if allocator.page_table.is_none() {
return Err(Error::NotInitialized);
}
aligned_size = (size + 4095) & !4095;
start_addr = allocator.find_free_area(aligned_size)?;
}
let mut allocator = VMALLOC_ALLOCATOR.lock();
let page_table = allocator.page_table.as_mut().unwrap();
// Map virtual to physical pages
let pages_needed = aligned_size / 4096;
for i in 0..pages_needed {
let virt_addr = VirtAddr::new(start_addr + i * 4096);
let phys_addr = PhysAddr::new(phys_addr.as_usize() + i * 4096);
page_table.map_page(
virt_addr,
phys_addr,
PageTableFlags::kernel_page() | PageTableFlags::NO_EXECUTE,
)?;
}
let end_addr = start_addr + aligned_size;
let area = VmallocArea {
start: VirtAddr::new(start_addr),
end: VirtAddr::new(end_addr),
size: aligned_size,
pages: alloc::vec![], // We don't own these pages
};
allocator.areas.insert(start_addr, area);
Ok(VirtAddr::new(start_addr))
}
pub fn vmap(pages: &[PhysAddr], count: usize) -> Result<VirtAddr> {
let size = count * 4096;
let mut allocator = VMALLOC_ALLOCATOR.lock();
// Find virtual address space
let start_addr = allocator.find_free_area(size)?;
let area = VmallocArea {
start: VirtAddr::new(start_addr),
end: VirtAddr::new(start_addr + size),
size,
pages: pages.to_vec(),
};
allocator.areas.insert(start_addr, area);
// TODO: Set up page table mappings
Ok(VirtAddr::new(start_addr))
}
/// Unmap virtual memory
pub fn vunmap(addr: VirtAddr) {
vfree(addr);
}
/// Initialize vmalloc allocator
pub fn init() -> Result<()> {
let mut allocator = VMALLOC_ALLOCATOR.lock();
allocator.init()
}

24
kernel/src/module.rs Archivo normal
Ver fichero

@@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel module support
use crate::error::Result;
/// Module metadata
pub struct ThisModule {
pub name: &'static str,
pub author: &'static str,
pub description: &'static str,
pub license: &'static str,
}
/// Trait for kernel modules
pub trait Module: Sized {
/// Initialize the module
fn init(module: &'static ThisModule) -> Result<Self>;
/// Clean up the module
fn exit(module: &'static ThisModule) {
// Default implementation does nothing
}
}

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

@@ -0,0 +1,327 @@
// SPDX-License-Identifier: GPL-2.0
//! Dynamic module loading system
use alloc::{
collections::BTreeMap,
string::{String, ToString},
vec::Vec,
};
use crate::error::Result;
use crate::sync::Spinlock;
use crate::{error, info, warn};
/// 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(())
}

727
kernel/src/network.rs Archivo normal
Ver fichero

@@ -0,0 +1,727 @@
// SPDX-License-Identifier: GPL-2.0
//! Network stack implementation
use alloc::{
boxed::Box,
collections::BTreeMap,
collections::VecDeque,
string::{String, ToString},
vec::Vec,
};
use core::fmt;
use crate::error::{Error, Result};
use crate::sync::Spinlock;
/// Network protocol types
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ProtocolType {
Ethernet = 0x0001,
IPv4 = 0x0800,
IPv6 = 0x86DD,
ARP = 0x0806,
TCP = 6,
UDP = 17,
ICMP = 2, // Different value to avoid conflict with Ethernet
ICMPv6 = 58,
}
/// MAC address (6 bytes)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacAddress([u8; 6]);
impl MacAddress {
pub const fn new(bytes: [u8; 6]) -> Self {
Self(bytes)
}
pub const fn broadcast() -> Self {
Self([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF])
}
pub const fn zero() -> Self {
Self([0, 0, 0, 0, 0, 0])
}
pub fn bytes(&self) -> &[u8; 6] {
&self.0
}
pub fn is_broadcast(&self) -> bool {
*self == Self::broadcast()
}
pub fn is_multicast(&self) -> bool {
(self.0[0] & 0x01) != 0
}
}
impl fmt::Display for MacAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
)
}
}
/// IPv4 address
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Ipv4Address([u8; 4]);
impl Ipv4Address {
pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
Self([a, b, c, d])
}
pub const fn from_bytes(bytes: [u8; 4]) -> Self {
Self(bytes)
}
pub const fn localhost() -> Self {
Self([127, 0, 0, 1])
}
pub const fn broadcast() -> Self {
Self([255, 255, 255, 255])
}
pub const fn any() -> Self {
Self([0, 0, 0, 0])
}
pub fn bytes(&self) -> &[u8; 4] {
&self.0
}
pub fn to_u32(&self) -> u32 {
u32::from_be_bytes(self.0)
}
pub fn from_u32(addr: u32) -> Self {
Self(addr.to_be_bytes())
}
pub fn is_private(&self) -> bool {
matches!(self.0, [10, ..] | [172, 16..=31, ..] | [192, 168, ..])
}
pub fn is_multicast(&self) -> bool {
(self.0[0] & 0xF0) == 0xE0
}
pub fn is_broadcast(&self) -> bool {
*self == Self::broadcast()
}
}
impl fmt::Display for Ipv4Address {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}.{}.{}", self.0[0], self.0[1], self.0[2], self.0[3])
}
}
/// Network packet buffer
#[derive(Debug, Clone)]
pub struct NetworkBuffer {
data: Vec<u8>,
len: usize,
protocol: ProtocolType,
source_mac: Option<MacAddress>,
dest_mac: Option<MacAddress>,
source_ip: Option<Ipv4Address>,
dest_ip: Option<Ipv4Address>,
source_port: Option<u16>,
dest_port: Option<u16>,
}
impl NetworkBuffer {
pub fn new(capacity: usize) -> Self {
Self {
data: Vec::with_capacity(capacity),
len: 0,
protocol: ProtocolType::Ethernet,
source_mac: None,
dest_mac: None,
source_ip: None,
dest_ip: None,
source_port: None,
dest_port: None,
}
}
pub fn from_data(data: Vec<u8>) -> Self {
let len = data.len();
Self {
data,
len,
protocol: ProtocolType::Ethernet,
source_mac: None,
dest_mac: None,
source_ip: None,
dest_ip: None,
source_port: None,
dest_port: None,
}
}
pub fn data(&self) -> &[u8] {
&self.data[..self.len]
}
pub fn data_mut(&mut self) -> &mut [u8] {
&mut self.data[..self.len]
}
pub fn len(&self) -> usize {
self.len
}
pub fn push(&mut self, byte: u8) -> Result<()> {
if self.len >= self.data.capacity() {
return Err(Error::OutOfMemory);
}
if self.len >= self.data.len() {
self.data.push(byte);
} else {
self.data[self.len] = byte;
}
self.len += 1;
Ok(())
}
pub fn extend_from_slice(&mut self, data: &[u8]) -> Result<()> {
if self.len + data.len() > self.data.capacity() {
return Err(Error::OutOfMemory);
}
for &byte in data {
self.push(byte)?;
}
Ok(())
}
pub fn set_protocol(&mut self, protocol: ProtocolType) {
self.protocol = protocol;
}
pub fn set_mac_addresses(&mut self, source: MacAddress, dest: MacAddress) {
self.source_mac = Some(source);
self.dest_mac = Some(dest);
}
pub fn set_ip_addresses(&mut self, source: Ipv4Address, dest: Ipv4Address) {
self.source_ip = Some(source);
self.dest_ip = Some(dest);
}
pub fn set_ports(&mut self, source: u16, dest: u16) {
self.source_port = Some(source);
self.dest_port = Some(dest);
}
}
/// Network interface
pub trait NetworkInterface: Send + Sync {
fn name(&self) -> &str;
fn ip_address(&self) -> Option<Ipv4Address>;
fn mac_address(&self) -> MacAddress;
fn mtu(&self) -> u16;
fn is_up(&self) -> bool;
fn send_packet(&mut self, buffer: &NetworkBuffer) -> Result<()>;
fn receive_packet(&mut self) -> Result<Option<NetworkBuffer>>;
fn set_up(&mut self, up: bool) -> Result<()>;
fn set_mac_address(&mut self, mac: MacAddress) -> Result<()>;
}
/// Network interface statistics
#[derive(Debug, Default, Clone)]
pub struct InterfaceStats {
pub bytes_sent: u64,
pub bytes_received: u64,
pub packets_sent: u64,
pub packets_received: u64,
pub errors: u64,
pub dropped: u64,
}
/// A loopback network interface.
#[derive(Debug)]
pub struct LoopbackInterface {
rx_queue: VecDeque<NetworkBuffer>,
up: bool,
}
impl LoopbackInterface {
pub fn new() -> Self {
Self {
rx_queue: VecDeque::new(),
up: true,
}
}
}
impl NetworkInterface for LoopbackInterface {
fn name(&self) -> &str {
"lo"
}
fn ip_address(&self) -> Option<Ipv4Address> {
Some(Ipv4Address::localhost())
}
fn mac_address(&self) -> MacAddress {
MacAddress::zero()
}
fn mtu(&self) -> u16 {
65535
}
fn is_up(&self) -> bool {
self.up
}
fn send_packet(&mut self, buffer: &NetworkBuffer) -> Result<()> {
if !self.up {
return Err(Error::NetworkDown);
}
self.rx_queue.push_back(buffer.clone());
Ok(())
}
fn receive_packet(&mut self) -> Result<Option<NetworkBuffer>> {
if !self.up {
return Ok(None);
}
Ok(self.rx_queue.pop_front())
}
fn set_up(&mut self, up: bool) -> Result<()> {
self.up = up;
Ok(())
}
fn set_mac_address(&mut self, _mac: MacAddress) -> Result<()> {
// The loopback interface doesn't have a real MAC address.
Ok(())
}
}
/// Network stack
struct PendingArpRequest {
packet: NetworkBuffer,
ip: Ipv4Address,
timestamp: u64,
}
pub struct NetworkStack {
interfaces: BTreeMap<String, Box<dyn NetworkInterface>>,
interface_stats: BTreeMap<String, InterfaceStats>,
routing_table: Vec<RouteEntry>,
arp_table: BTreeMap<Ipv4Address, MacAddress>,
pending_arp_requests: Vec<PendingArpRequest>,
}
/// Routing table entry
#[derive(Debug, Clone)]
pub struct RouteEntry {
pub destination: Ipv4Address,
pub netmask: Ipv4Address,
pub gateway: Option<Ipv4Address>,
pub interface: String,
pub metric: u32,
}
impl NetworkStack {
const fn new() -> Self {
Self {
interfaces: BTreeMap::new(),
interface_stats: BTreeMap::new(),
routing_table: Vec::new(),
arp_table: BTreeMap::new(),
pending_arp_requests: Vec::new(),
}
}
pub fn add_interface(&mut self, name: String, interface: Box<dyn NetworkInterface>) {
self.interface_stats
.insert(name.clone(), InterfaceStats::default());
self.interfaces.insert(name, interface);
}
pub fn remove_interface(&mut self, name: &str) -> Option<Box<dyn NetworkInterface>> {
self.interface_stats.remove(name);
self.interfaces.remove(name)
}
pub fn get_interface(&self, name: &str) -> Option<&dyn NetworkInterface> {
self.interfaces.get(name).map(|i| i.as_ref())
}
pub fn get_interface_mut<'a>(
&'a mut self,
name: &str,
) -> Option<&'a mut (dyn NetworkInterface + 'a)> {
if let Some(interface) = self.interfaces.get_mut(name) {
Some(interface.as_mut())
} else {
None
}
}
pub fn list_interfaces(&self) -> Vec<String> {
self.interfaces.keys().cloned().collect()
}
pub fn add_route(&mut self, route: RouteEntry) {
self.routing_table.push(route);
// Sort by metric (lower is better)
self.routing_table.sort_by_key(|r| r.metric);
}
pub fn find_route(&self, dest: Ipv4Address) -> Option<&RouteEntry> {
for route in &self.routing_table {
let dest_u32 = dest.to_u32();
let route_dest = route.destination.to_u32();
let netmask = route.netmask.to_u32();
if (dest_u32 & netmask) == (route_dest & netmask) {
return Some(route);
}
}
None
}
pub fn add_arp_entry(&mut self, ip: Ipv4Address, mac: MacAddress) {
self.arp_table.insert(ip, mac);
}
pub fn lookup_arp(&self, ip: Ipv4Address) -> Option<MacAddress> {
self.arp_table.get(&ip).copied()
}
pub fn send_packet(
&mut self,
dest: Ipv4Address,
data: &[u8],
protocol: ProtocolType,
) -> Result<()> {
// Clean up timed out ARP requests
let now = crate::time::get_time_ns();
self.pending_arp_requests
.retain(|req| now - req.timestamp < 10_000_000_000); // 10 seconds
// Find route (borrow self immutably)
let route = {
let route = self.find_route(dest).ok_or(Error::NetworkUnreachable)?;
route.clone() // Clone to avoid borrowing issues
};
// Look up MAC address first (borrow self immutably)
let dest_mac = if let Some(gateway) = route.gateway {
self.lookup_arp(gateway)
} else {
self.lookup_arp(dest)
};
let dest_mac = if let Some(mac) = dest_mac {
mac
} else {
// ARP lookup failed, send an ARP request and queue the packet
let interface = self
.get_interface(&route.interface)
.ok_or(Error::DeviceNotFound)?;
let arp_request = crate::arp::ArpPacket::new(
crate::arp::ArpOperation::Request,
interface.mac_address(),
interface.ip_address().unwrap_or(Ipv4Address::any()),
MacAddress::zero(),
dest,
);
let mut buffer = NetworkBuffer::new(28);
buffer.set_protocol(ProtocolType::ARP);
buffer.set_mac_addresses(interface.mac_address(), MacAddress::broadcast());
buffer.extend_from_slice(&arp_request.to_bytes())?;
let interface_mut = self
.get_interface_mut(&route.interface)
.ok_or(Error::DeviceNotFound)?;
interface_mut.send_packet(&buffer)?;
// Queue the original packet
let mut packet_to_queue = NetworkBuffer::new(data.len());
packet_to_queue.extend_from_slice(data)?;
packet_to_queue.set_protocol(protocol);
packet_to_queue.set_ip_addresses(Ipv4Address::any(), dest); // TODO: Set source IP
self.pending_arp_requests.push(PendingArpRequest {
packet: packet_to_queue,
ip: dest,
timestamp: crate::time::get_time_ns(),
});
return Ok(()); // We'll have to wait for the reply
};
// Get interface MAC address
let interface_mac = {
let interface = self
.get_interface(&route.interface)
.ok_or(Error::DeviceNotFound)?;
interface.mac_address()
};
// Build packet
let mut buffer = NetworkBuffer::new(1500);
buffer.set_protocol(protocol);
buffer.set_mac_addresses(interface_mac, dest_mac);
buffer.extend_from_slice(data)?;
// Send packet (borrow self mutably)
{
let interface = self
.get_interface_mut(&route.interface)
.ok_or(Error::DeviceNotFound)?;
interface.send_packet(&buffer)?;
}
// Update statistics
if let Some(stats) = self.interface_stats.get_mut(&route.interface) {
stats.packets_sent += 1;
stats.bytes_sent += buffer.len() as u64;
}
Ok(())
}
pub fn receive_and_handle_packets(&mut self) -> Result<Vec<NetworkBuffer>> {
let mut received_packets = Vec::new();
let mut unhandled_packets = Vec::new();
// First, receive all packets from all interfaces
for (name, interface) in &mut self.interfaces {
while let Some(packet) = interface.receive_packet()? {
if let Some(stats) = self.interface_stats.get_mut(name) {
stats.packets_received += 1;
stats.bytes_received += packet.len() as u64;
}
received_packets.push((name.clone(), packet));
}
}
// Now, process the received packets
for (interface_name, packet) in received_packets {
if packet.protocol == ProtocolType::ARP {
if let Ok(arp_packet) =
crate::arp::ArpPacket::from_bytes(packet.data())
{
self.handle_arp_packet(&arp_packet, &interface_name)?;
}
} else if packet.protocol == ProtocolType::ICMP {
if let Some(source_ip) = packet.source_ip {
self.handle_icmp_packet(source_ip, packet.data())?;
}
} else {
unhandled_packets.push(packet);
}
}
Ok(unhandled_packets)
}
pub fn receive_packets(&mut self) -> Result<Vec<NetworkBuffer>> {
self.receive_and_handle_packets()
}
pub fn get_interface_stats(&self, name: &str) -> Option<&InterfaceStats> {
self.interface_stats.get(name)
}
fn handle_arp_packet(
&mut self,
packet: &crate::arp::ArpPacket,
interface_name: &str,
) -> Result<()> {
// Add the sender to the ARP table
self.add_arp_entry(packet.spa, packet.sha);
// If it's a request for us, send a reply
if u16::from_be_bytes(packet.oper) == crate::arp::ArpOperation::Request as u16 {
if let Some(interface) = self.get_interface(interface_name) {
if let Some(ip_addr) = interface.ip_address() {
if ip_addr == packet.tpa {
let reply = crate::arp::ArpPacket::new(
crate::arp::ArpOperation::Reply,
interface.mac_address(),
ip_addr,
packet.sha,
packet.spa,
);
let mut buffer = NetworkBuffer::new(28);
buffer.set_protocol(ProtocolType::ARP);
buffer.set_mac_addresses(
interface.mac_address(),
packet.sha,
);
buffer.extend_from_slice(&reply.to_bytes())?;
if let Some(interface) =
self.get_interface_mut(interface_name)
{
interface.send_packet(&buffer)?;
}
}
}
}
}
// Check for pending packets
let mut packets_to_send = Vec::new();
let mut still_pending = Vec::new();
for pending in self.pending_arp_requests.drain(..) {
if pending.ip == packet.spa {
packets_to_send.push(pending);
} else {
still_pending.push(pending);
}
}
self.pending_arp_requests = still_pending;
for pending in packets_to_send {
self.send_packet(
pending.ip,
pending.packet.data(),
pending.packet.protocol,
)?;
}
Ok(())
}
fn handle_icmp_packet(&mut self, source_ip: Ipv4Address, packet: &[u8]) -> Result<()> {
if packet.len() < 8 {
return Err(Error::InvalidArgument);
}
let icmp_type = packet[0];
if icmp_type == crate::icmp::IcmpType::EchoRequest as u8 {
let mut reply = packet.to_vec();
reply[0] = crate::icmp::IcmpType::EchoReply as u8;
// Recalculate checksum
let checksum = utils::calculate_checksum(&reply);
reply[2] = (checksum >> 8) as u8;
reply[3] = (checksum & 0xFF) as u8;
self.send_packet(source_ip, &reply, ProtocolType::ICMP)?;
}
Ok(())
}
}
/// Global network stack
pub static NETWORK_STACK: Spinlock<Option<NetworkStack>> = Spinlock::new(None);
/// Initialize network stack
pub fn init() -> Result<()> {
let mut stack = NETWORK_STACK.lock();
let mut network_stack = NetworkStack::new();
// Add loopback interface
let loopback = LoopbackInterface::new();
network_stack.add_interface("lo".to_string(), Box::new(loopback));
// Add route for loopback
network_stack.add_route(RouteEntry {
destination: Ipv4Address::new(127, 0, 0, 0),
netmask: Ipv4Address::new(255, 0, 0, 0),
gateway: None,
interface: "lo".to_string(),
metric: 0,
});
// Add ARP entry for loopback
network_stack.add_arp_entry(Ipv4Address::localhost(), MacAddress::zero());
*stack = Some(network_stack);
crate::info!("Network stack initialized");
Ok(())
}
/// Add a network interface
pub fn add_network_interface(name: String, interface: Box<dyn NetworkInterface>) -> Result<()> {
let mut stack_opt = NETWORK_STACK.lock();
if let Some(ref mut stack) = *stack_opt {
stack.add_interface(name, interface);
Ok(())
} else {
Err(Error::NotInitialized)
}
}
pub mod utils {
/// Calculate checksum
pub fn calculate_checksum(data: &[u8]) -> u16 {
let mut sum = 0u32;
// Sum all 16-bit words
for chunk in data.chunks(2) {
if chunk.len() == 2 {
sum += ((chunk[0] as u32) << 8) + (chunk[1] as u32);
} else {
sum += (chunk[0] as u32) << 8;
}
}
// Add carry
while sum >> 16 != 0 {
sum = (sum & 0xFFFF) + (sum >> 16);
}
// One's complement
!sum as u16
}
}
/// Send a packet
pub fn send_packet(dest: Ipv4Address, data: &[u8], protocol: ProtocolType) -> Result<()> {
let mut stack_opt = NETWORK_STACK.lock();
if let Some(ref mut stack) = *stack_opt {
stack.send_packet(dest, data, protocol)
} else {
Err(Error::NotInitialized)
}
}
/// Add a route
pub fn add_route(
destination: Ipv4Address,
netmask: Ipv4Address,
gateway: Option<Ipv4Address>,
interface: String,
metric: u32,
) -> Result<()> {
let mut stack_opt = NETWORK_STACK.lock();
if let Some(ref mut stack) = *stack_opt {
stack.add_route(RouteEntry {
destination,
netmask,
gateway,
interface,
metric,
});
Ok(())
} else {
Err(Error::NotInitialized)
}
}
/// Add an ARP entry
pub fn add_arp_entry(ip: Ipv4Address, mac: MacAddress) -> Result<()> {
let mut stack_opt = NETWORK_STACK.lock();
if let Some(ref mut stack) = *stack_opt {
stack.add_arp_entry(ip, mac);
Ok(())
} else {
Err(Error::NotInitialized)
}
}

122
kernel/src/panic.rs Archivo normal
Ver fichero

@@ -0,0 +1,122 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel panic handler
use core::fmt::Write;
use core::panic::PanicInfo;
/// Panic handler
#[panic_handler]
pub fn panic_handler(info: &PanicInfo) -> ! {
// Disable interrupts
#[cfg(target_arch = "x86_64")]
unsafe {
core::arch::asm!("cli");
}
// Print panic information
let mut writer = PanicWriter;
writeln!(writer, "\n\n=== KERNEL PANIC ===").ok();
if let Some(location) = info.location() {
writeln!(
writer,
"Panic at {}:{}:{}",
location.file(),
location.line(),
location.column()
)
.ok();
}
let message = info.message();
writeln!(writer, "Message: {}", message).ok();
writeln!(writer, "===================\n").ok();
// Print stack trace
print_stack_trace(&mut writer);
// Save panic information to system log
save_panic_info(info);
// Halt the system
loop {
#[cfg(target_arch = "x86_64")]
unsafe {
core::arch::asm!("hlt");
}
#[cfg(not(target_arch = "x86_64"))]
core::hint::spin_loop();
}
}
/// Print a simple stack trace
fn print_stack_trace<W: core::fmt::Write>(writer: &mut W) {
writeln!(writer, "Stack trace:").ok();
// Get current frame pointer
let mut rbp: *const usize;
unsafe {
core::arch::asm!("mov {}, rbp", out(reg) rbp);
}
// Walk the stack (simplified)
let mut frame_count = 0;
while !rbp.is_null() && frame_count < 10 {
unsafe {
// Read return address from stack frame
let ret_addr = rbp.add(1).read_volatile();
writeln!(writer, " #{}: 0x{:016x}", frame_count, ret_addr).ok();
// Move to previous frame
rbp = rbp.read_volatile() as *const usize;
frame_count += 1;
// Safety check to avoid infinite loops
if (rbp as usize) < 0x1000 || (rbp as usize) > 0x7FFFFFFFFFFF {
break;
}
}
}
}
/// Save panic information to system log
fn save_panic_info(info: &core::panic::PanicInfo) {
// In a real implementation, this would write to a persistent log
// For now, we'll just store it in memory for potential retrieval
if let Some(location) = info.location() {
crate::info!(
"PANIC LOGGED: {}:{}:{} - {}",
location.file(),
location.line(),
location.column(),
info.message()
);
} else {
crate::info!("PANIC LOGGED: {}", info.message());
}
}
/// Writer for panic messages
struct PanicWriter;
impl Write for PanicWriter {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
// Write directly to VGA buffer or serial port
for byte in s.bytes() {
#[cfg(target_arch = "x86_64")]
unsafe {
// Write to serial port (COM1)
core::arch::asm!(
"out dx, al",
in("dx") 0x3f8u16,
in("al") byte,
);
}
}
Ok(())
}
}

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

@@ -0,0 +1,317 @@
// SPDX-License-Identifier: GPL-2.0
//! Performance monitoring and profiling
use alloc::{collections::BTreeMap, format, string::String, vec::Vec};
use core::sync::atomic::{AtomicU64, Ordering};
use crate::error::Result;
use crate::sync::Spinlock;
use crate::types::Jiffies;
/// 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);
}
}

110
kernel/src/prelude.rs Archivo normal
Ver fichero

@@ -0,0 +1,110 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel prelude - commonly used types and traits
// Re-export macros
pub use alloc::vec;
// Re-export common alloc types
pub use alloc::{
boxed::Box,
collections::{BTreeMap, BTreeSet},
format,
string::{String, ToString},
vec::Vec,
};
// Re-export core types
pub use core::{
fmt, mem,
option::Option::{self, None, Some},
ptr,
result::Result as CoreResult,
slice, str,
};
pub use crate::device::Device;
pub use crate::driver::{BlockDriverOps, CharDriverOps, Driver};
pub use crate::error::{Error, Result};
pub use crate::memory::{PageTable, PhysAddr, UserPtr, UserSlicePtr, VirtAddr};
pub use crate::process::{Process, Thread};
pub use crate::sync::{Mutex, RwLock, Spinlock};
pub use crate::task::Task;
pub use crate::types::*;
/// Print macros for kernel logging
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ($crate::console::_print(format_args!($($arg)*)));
}
#[macro_export]
macro_rules! println {
() => ($crate::print!("\n"));
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
}
#[macro_export]
macro_rules! kprint {
($($arg:tt)*) => ($crate::console::_kprint(format_args!($($arg)*)));
}
#[macro_export]
macro_rules! kprintln {
() => ($crate::kprint!("\n"));
($($arg:tt)*) => ($crate::kprint!("[KERNEL] {}\n", format_args!($($arg)*)));
}
#[macro_export]
macro_rules! debug {
($($arg:tt)*) => {
#[cfg(feature = "debug")]
$crate::kprintln!("[DEBUG] {}", format_args!($($arg)*))
};
}
#[macro_export]
macro_rules! info {
($($arg:tt)*) => ($crate::kprintln!("[INFO] {}", format_args!($($arg)*)));
}
#[macro_export]
macro_rules! warn {
($($arg:tt)*) => ($crate::kprintln!("[WARN] {}", format_args!($($arg)*)));
}
#[macro_export]
macro_rules! error {
($($arg:tt)*) => ($crate::kprintln!("[ERROR] {}", format_args!($($arg)*)));
}
/// Module definition macro
#[macro_export]
macro_rules! module {
(
type:
$type:ty,name:
$name:expr,author:
$author:expr,description:
$description:expr,license:
$license:expr $(,)?
) => {
static __THIS_MODULE: $crate::module::ThisModule = $crate::module::ThisModule {
name: $name,
author: $author,
description: $description,
license: $license,
};
#[no_mangle]
pub extern "C" fn init_module() -> core::ffi::c_int {
match <$type as $crate::module::Module>::init(&__THIS_MODULE) {
Ok(_) => 0,
Err(e) => e.to_errno(),
}
}
#[no_mangle]
pub extern "C" fn cleanup_module() {
<$type as $crate::module::Module>::exit(&__THIS_MODULE)
}
};
}

378
kernel/src/process.rs Archivo normal
Ver fichero

@@ -0,0 +1,378 @@
// SPDX-License-Identifier: GPL-2.0
//! Process and thread management
use alloc::{
collections::BTreeMap,
string::{String, ToString},
vec::Vec,
};
use core::sync::atomic::{AtomicU32, Ordering};
use crate::arch::x86_64::context::Context;
use crate::error::{Error, Result};
use crate::memory::VirtAddr;
use crate::sync::Spinlock;
use crate::types::{Gid, Pid, Tid, Uid};
/// Process state - compatible with Linux kernel
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProcessState {
Running,
Sleeping,
Stopped,
Zombie,
Dead,
}
/// Process structure - similar to Linux task_struct
#[derive(Debug, Clone)]
pub struct Process {
pub pid: Pid,
pub parent: Option<Pid>,
pub state: ProcessState,
pub uid: Uid,
pub gid: Gid,
pub name: String,
pub threads: Vec<Thread>,
pub memory_map: Option<VirtAddr>, // Points to mm_struct equivalent
pub files: Vec<u32>, // File descriptor table
pub signal_pending: bool,
pub exit_code: i32,
}
impl Process {
pub fn new(pid: Pid, name: String, uid: Uid, gid: Gid) -> Self {
Self {
pid,
parent: None,
state: ProcessState::Running,
uid,
gid,
name,
threads: Vec::new(),
memory_map: None,
files: Vec::new(),
signal_pending: false,
exit_code: 0,
}
}
/// Add a thread to this process
pub fn add_thread(&mut self, thread: Thread) {
self.threads.push(thread);
}
/// Get the main thread
pub fn main_thread(&self) -> Option<&Thread> {
self.threads.first()
}
/// Set process state
pub fn set_state(&mut self, state: ProcessState) {
self.state = state;
}
/// Check if process is running
pub fn is_running(&self) -> bool {
self.state == ProcessState::Running
}
/// Fork the current process (create a copy)
pub fn fork(&self) -> Result<Process> {
let new_pid = allocate_pid();
let mut child = self.clone();
child.pid = new_pid;
child.parent = Some(self.pid);
child.state = ProcessState::Running;
// TODO: Copy memory space (copy-on-write)
// TODO: Copy file descriptor table
// TODO: Set up new page tables
Ok(child)
}
/// Execute a new program in this process
pub fn exec(&mut self, program_path: &str, args: Vec<String>) -> Result<()> {
// TODO: Load program from filesystem
// TODO: Set up new memory layout
// TODO: Initialize stack with arguments
// TODO: Set entry point
self.name = program_path.to_string();
Ok(())
}
/// Terminate the process with given exit code
pub fn exit(&mut self, exit_code: i32) {
self.state = ProcessState::Zombie;
self.exit_code = exit_code;
// TODO: Free memory
// TODO: Close file descriptors
// TODO: Notify parent
// TODO: Reparent children to init
}
/// Send a signal to the process
pub fn send_signal(&mut self, signal: i32) -> Result<()> {
match signal {
9 => {
// SIGKILL
self.state = ProcessState::Dead;
}
15 => {
// SIGTERM
self.signal_pending = true;
// TODO: Add to signal queue
}
_ => {
// TODO: Handle other signals
}
}
Ok(())
}
/// Wait for child processes
pub fn wait(&self) -> Result<(Pid, i32)> {
// TODO: Block until child exits
// TODO: Return child PID and exit status
Err(Error::ECHILD)
}
}
/// Thread structure - Linux-compatible
#[derive(Debug, Clone)]
pub struct Thread {
pub tid: Tid,
pub process_pid: Pid,
pub state: ProcessState,
pub stack_pointer: VirtAddr,
pub instruction_pointer: VirtAddr,
pub priority: i32,
pub nice: i32, // Nice value (-20 to 19)
pub cpu_time: u64, // Nanoseconds
pub context: Context,
}
impl Thread {
pub fn new(tid: Tid, process_pid: Pid, priority: i32) -> Self {
Self {
tid,
process_pid,
state: ProcessState::Running,
stack_pointer: VirtAddr::new(0),
instruction_pointer: VirtAddr::new(0),
priority,
nice: 0,
cpu_time: 0,
context: Context::new(),
}
}
/// Set thread state
pub fn set_state(&mut self, state: ProcessState) {
self.state = state;
}
/// Update CPU time
pub fn add_cpu_time(&mut self, time: u64) {
self.cpu_time += time;
}
}
/// Global process table
pub static PROCESS_TABLE: Spinlock<ProcessTable> = Spinlock::new(ProcessTable::new());
static NEXT_PID: AtomicU32 = AtomicU32::new(1);
static NEXT_TID: AtomicU32 = AtomicU32::new(1);
/// Process table implementation
pub struct ProcessTable {
processes: BTreeMap<Pid, Process>,
current_process: Option<Pid>,
}
impl ProcessTable {
const fn new() -> Self {
Self {
processes: BTreeMap::new(),
current_process: None,
}
}
pub fn add_process(&mut self, process: Process) {
let pid = process.pid;
self.processes.insert(pid, process);
if self.current_process.is_none() {
self.current_process = Some(pid);
}
}
fn get_process(&self, pid: Pid) -> Option<&Process> {
self.processes.get(&pid)
}
fn get_process_mut(&mut self, pid: Pid) -> Option<&mut Process> {
self.processes.get_mut(&pid)
}
#[allow(dead_code)]
fn remove_process(&mut self, pid: Pid) -> Option<Process> {
let process = self.processes.remove(&pid);
if self.current_process == Some(pid) {
self.current_process = self.processes.keys().next().copied();
}
process
}
fn list_processes(&self) -> Vec<Pid> {
self.processes.keys().copied().collect()
}
pub fn find_thread(&self, tid: Tid) -> Option<&Thread> {
for process in self.processes.values() {
for thread in &process.threads {
if thread.tid == tid {
return Some(thread);
}
}
}
None
}
pub fn find_thread_mut(&mut self, tid: Tid) -> Option<&mut Thread> {
for process in self.processes.values_mut() {
for thread in &mut process.threads {
if thread.tid == tid {
return Some(thread);
}
}
}
None
}
pub fn find_two_threads_mut(
&mut self,
tid1: Tid,
tid2: Tid,
) -> (Option<&mut Thread>, Option<&mut Thread>) {
if tid1 == tid2 {
let t = self.find_thread_mut(tid1);
return (t, None);
}
// This is a bit inefficient but safe
// We can't easily return two mutable references to the same structure
// But since they are in different processes or different threads, they are distinct memory locations.
// We can use unsafe to cheat the borrow checker, knowing that tid1 != tid2.
let ptr = self as *mut ProcessTable;
unsafe {
let t1 = (*ptr).find_thread_mut(tid1);
let t2 = (*ptr).find_thread_mut(tid2);
(t1, t2)
}
}
}
/// Allocate a new PID
pub fn allocate_pid() -> Pid {
Pid(NEXT_PID.fetch_add(1, Ordering::SeqCst))
}
/// Allocate a new TID
pub fn allocate_tid() -> Tid {
Tid(NEXT_TID.fetch_add(1, Ordering::SeqCst))
}
/// Create a new process
pub fn create_process(name: String, uid: Uid, gid: Gid) -> Result<Pid> {
let pid = allocate_pid();
let mut process = Process::new(pid, name, uid, gid);
// Create main thread
let tid = allocate_tid();
let main_thread = Thread::new(tid, pid, 0);
process.add_thread(main_thread);
let mut table = PROCESS_TABLE.lock();
table.add_process(process);
Ok(pid)
}
/// Add a thread to the kernel process (PID 0)
pub fn add_kernel_thread(tid: Tid, context: Context, stack_pointer: VirtAddr) -> Result<()> {
let mut table = PROCESS_TABLE.lock();
if let Some(process) = table.get_process_mut(Pid(0)) {
let mut thread = Thread::new(tid, Pid(0), 0);
thread.context = context;
thread.stack_pointer = stack_pointer;
process.add_thread(thread);
Ok(())
} else {
Err(Error::NotFound)
}
}
/// Get current process PID
pub fn current_process_pid() -> Option<Pid> {
let table = PROCESS_TABLE.lock();
table.current_process
}
/// Get current process object
pub fn current_process() -> Option<Process> {
let table = PROCESS_TABLE.lock();
if let Some(pid) = table.current_process {
table.get_process(pid).cloned()
} else {
None
}
}
/// Get process by PID
pub fn find_process(pid: Pid) -> Option<Process> {
let table = PROCESS_TABLE.lock();
table.get_process(pid).cloned()
}
/// Kill a process
pub fn kill_process(pid: Pid, signal: i32) -> Result<()> {
let mut table = PROCESS_TABLE.lock();
if let Some(process) = table.get_process_mut(pid) {
process.set_state(ProcessState::Dead);
process.exit_code = signal;
Ok(())
} else {
Err(Error::NotFound)
}
}
/// List all processes
pub fn list_processes() -> Vec<Pid> {
let table = PROCESS_TABLE.lock();
table.list_processes()
}
/// Initialize process management
pub fn init_process_management() -> Result<()> {
init()
}
/// Initialize the process subsystem
pub fn init() -> Result<()> {
// Initialize the process table and create kernel process (PID 0)
let kernel_pid = create_process(
"kernel".to_string(),
Uid(0), // root
Gid(0), // root
)?;
crate::info!(
"Process management initialized with kernel PID {}",
kernel_pid.0
);
Ok(())
}

670
kernel/src/scheduler.rs Archivo normal
Ver fichero

@@ -0,0 +1,670 @@
// SPDX-License-Identifier: GPL-2.0
//! Task scheduler compatible with Linux kernel CFS (Completely Fair Scheduler)
use alloc::{
collections::{BTreeMap, VecDeque},
vec::Vec,
};
use core::sync::atomic::{AtomicU64, Ordering};
use crate::arch::x86_64::context::{switch_context, Context};
use crate::error::{Error, Result};
use crate::process::{Thread, PROCESS_TABLE};
use crate::sync::Spinlock;
use crate::time;
use crate::types::Tid;
/// Scheduler policies - Linux compatible
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SchedulerPolicy {
Normal = 0, // SCHED_NORMAL
Fifo = 1, // SCHED_FIFO
RoundRobin = 2, // SCHED_RR
Batch = 3, // SCHED_BATCH
Idle = 5, // SCHED_IDLE
Deadline = 6, // SCHED_DEADLINE
}
/// Scheduler priority levels
pub const MAX_PRIO: i32 = 140;
pub const MAX_USER_RT_PRIO: i32 = 100;
pub const MAX_RT_PRIO: i32 = MAX_USER_RT_PRIO;
pub const DEFAULT_PRIO: i32 = MAX_RT_PRIO + 20;
pub const MIN_NICE: i32 = -20;
pub const MAX_NICE: i32 = 19;
/// Convert nice value to priority
pub fn nice_to_prio(nice: i32) -> i32 {
DEFAULT_PRIO + nice
}
/// Convert priority to nice value
pub fn prio_to_nice(prio: i32) -> i32 {
prio - DEFAULT_PRIO
}
/// Scheduler entity - represents a schedulable unit
#[derive(Debug, Clone)]
pub struct SchedEntity {
pub tid: Tid,
pub policy: SchedulerPolicy,
pub priority: i32,
pub nice: i32,
pub vruntime: u64, // Virtual runtime for CFS
pub exec_start: u64, // Last execution start time
pub sum_exec_runtime: u64, // Total execution time
pub prev_sum_exec_runtime: u64,
pub load_weight: u32, // Load weight for this entity
pub runnable_weight: u32,
pub on_rq: bool, // On run queue?
}
impl SchedEntity {
pub fn new(tid: Tid, policy: SchedulerPolicy, nice: i32) -> Self {
let priority = nice_to_prio(nice);
Self {
tid,
policy,
priority,
nice,
vruntime: 0,
exec_start: 0,
sum_exec_runtime: 0,
prev_sum_exec_runtime: 0,
load_weight: nice_to_weight(nice),
runnable_weight: nice_to_weight(nice),
on_rq: false,
}
}
/// Update virtual runtime
pub fn update_vruntime(&mut self, delta: u64) {
// Virtual runtime is weighted by load
let weighted_delta = delta * 1024 / self.load_weight as u64;
self.vruntime += weighted_delta;
}
}
/// Convert nice value to load weight (Linux compatible)
fn nice_to_weight(nice: i32) -> u32 {
// Linux nice-to-weight table (simplified)
match nice {
-20 => 88761,
-19 => 71755,
-18 => 56483,
-17 => 46273,
-16 => 36291,
-15 => 29154,
-14 => 23254,
-13 => 18705,
-12 => 14949,
-11 => 11916,
-10 => 9548,
-9 => 7620,
-8 => 6100,
-7 => 4904,
-6 => 3906,
-5 => 3121,
-4 => 2501,
-3 => 1991,
-2 => 1586,
-1 => 1277,
0 => 1024, // Default weight
1 => 820,
2 => 655,
3 => 526,
4 => 423,
5 => 335,
6 => 272,
7 => 215,
8 => 172,
9 => 137,
10 => 110,
11 => 87,
12 => 70,
13 => 56,
14 => 45,
15 => 36,
16 => 29,
17 => 23,
18 => 18,
19 => 15,
_ => 1024, // Default for out-of-range values
}
}
/// CFS (Completely Fair Scheduler) run queue
#[derive(Debug)]
pub struct CfsRunQueue {
tasks_timeline: BTreeMap<u64, SchedEntity>, // Red-black tree equivalent
min_vruntime: u64,
nr_running: u32,
load_weight: u64,
runnable_weight: u64,
}
impl CfsRunQueue {
pub fn new() -> Self {
Self {
tasks_timeline: BTreeMap::new(),
min_vruntime: 0,
nr_running: 0,
load_weight: 0,
runnable_weight: 0,
}
}
/// Add task to run queue
pub fn enqueue_task(&mut self, mut se: SchedEntity) {
// Place entity in timeline
if !se.on_rq {
se.on_rq = true;
// Ensure vruntime is not too far behind
if se.vruntime < self.min_vruntime {
se.vruntime = self.min_vruntime;
}
self.tasks_timeline.insert(se.vruntime, se.clone());
self.nr_running += 1;
self.load_weight += se.load_weight as u64;
self.runnable_weight += se.runnable_weight as u64;
}
}
/// Remove task from run queue
pub fn dequeue_task(&mut self, se: &SchedEntity) -> bool {
if se.on_rq {
self.tasks_timeline.remove(&se.vruntime);
self.nr_running -= 1;
self.load_weight -= se.load_weight as u64;
self.runnable_weight -= se.runnable_weight as u64;
true
} else {
false
}
}
/// Pick next task to run
pub fn pick_next_task(&mut self) -> Option<SchedEntity> {
// Pick leftmost task (smallest vruntime)
if let Some((vruntime, se)) = self.tasks_timeline.iter().next() {
let se = se.clone();
let vruntime = *vruntime;
self.tasks_timeline.remove(&vruntime);
self.nr_running -= 1;
self.load_weight -= se.load_weight as u64;
self.runnable_weight -= se.runnable_weight as u64;
// Update min_vruntime
if let Some((next_vruntime, _)) = self.tasks_timeline.iter().next() {
self.min_vruntime =
core::cmp::max(self.min_vruntime, *next_vruntime);
} else {
self.min_vruntime = se.vruntime;
}
Some(se)
} else {
None
}
}
/// Update minimum virtual runtime
pub fn update_min_vruntime(&mut self) {
if let Some((&next_vruntime, _)) = self.tasks_timeline.iter().next() {
self.min_vruntime = core::cmp::max(self.min_vruntime, next_vruntime);
}
}
}
/// Real-time run queue
#[derive(Debug)]
pub struct RtRunQueue {
runqueue: VecDeque<SchedEntity>,
nr_running: u32,
}
impl RtRunQueue {
pub const fn new() -> Self {
Self {
runqueue: VecDeque::new(),
nr_running: 0,
}
}
pub fn enqueue_task(&mut self, se: SchedEntity) {
self.runqueue.push_back(se);
self.nr_running += 1;
}
pub fn dequeue_task(&mut self, se: &SchedEntity) -> bool {
if let Some(pos) = self.runqueue.iter().position(|task| task.tid == se.tid) {
self.nr_running -= 1;
self.runqueue.remove(pos);
true
} else {
false
}
}
pub fn pick_next_task(&mut self) -> Option<SchedEntity> {
if self.nr_running > 0 {
self.nr_running -= 1;
self.runqueue.pop_front()
} else {
None
}
}
}
/// Per-CPU run queue
#[derive(Debug)]
pub struct RunQueue {
pub cpu: u32,
pub nr_running: u32,
pub current: Option<SchedEntity>,
pub cfs: CfsRunQueue,
pub rt: RtRunQueue,
pub idle_task: Option<SchedEntity>,
pub clock: u64,
pub clock_task: u64,
}
impl RunQueue {
pub fn new(cpu: u32) -> Self {
Self {
cpu,
nr_running: 0,
current: None,
cfs: CfsRunQueue::new(),
rt: RtRunQueue::new(),
idle_task: None,
clock: 0,
clock_task: 0,
}
}
/// Update run queue clock
pub fn update_rq_clock(&mut self) {
self.clock = time::get_time_ns();
self.clock_task = self.clock;
}
/// Enqueue a task
pub fn enqueue_task(&mut self, se: SchedEntity) {
match se.policy {
SchedulerPolicy::Normal
| SchedulerPolicy::Batch
| SchedulerPolicy::Idle => {
self.cfs.enqueue_task(se);
}
SchedulerPolicy::Fifo | SchedulerPolicy::RoundRobin => {
self.rt.enqueue_task(se);
}
SchedulerPolicy::Deadline => {
// TODO: implement deadline scheduler
self.cfs.enqueue_task(se);
}
}
self.nr_running += 1;
}
/// Dequeue a task
pub fn dequeue_task(&mut self, se: &SchedEntity) -> bool {
let result = match se.policy {
SchedulerPolicy::Normal
| SchedulerPolicy::Batch
| SchedulerPolicy::Idle => self.cfs.dequeue_task(se),
SchedulerPolicy::Fifo | SchedulerPolicy::RoundRobin => {
self.rt.dequeue_task(se)
}
SchedulerPolicy::Deadline => self.cfs.dequeue_task(se),
};
if result {
self.nr_running -= 1;
}
result
}
/// Pick next task to run
pub fn pick_next_task(&mut self) -> Option<SchedEntity> {
// Real-time tasks have priority
if let Some(se) = self.rt.pick_next_task() {
return Some(se);
}
// Then CFS tasks
if let Some(se) = self.cfs.pick_next_task() {
return Some(se);
}
// Finally, idle task
self.idle_task.clone()
}
}
/// Global scheduler state
static SCHEDULER: Spinlock<Scheduler> = Spinlock::new(Scheduler::new());
static SCHEDULE_CLOCK: AtomicU64 = AtomicU64::new(0);
/// Main scheduler structure
struct Scheduler {
run_queues: Vec<RunQueue>,
nr_cpus: u32,
entities: BTreeMap<Tid, SchedEntity>,
need_resched: bool,
cfs: CfsRunQueue,
rt: RtRunQueue,
current: Option<Tid>,
nr_switches: u64,
}
impl Scheduler {
const fn new() -> Self {
Self {
run_queues: Vec::new(),
nr_cpus: 1, // Single CPU for now
entities: BTreeMap::new(),
need_resched: false,
cfs: CfsRunQueue {
tasks_timeline: BTreeMap::new(),
min_vruntime: 0,
nr_running: 0,
load_weight: 0,
runnable_weight: 0,
},
rt: RtRunQueue {
runqueue: VecDeque::new(),
nr_running: 0,
},
current: None,
nr_switches: 0,
}
}
fn init(&mut self) -> Result<()> {
// Create run queues for each CPU
for cpu in 0..self.nr_cpus {
let mut rq = RunQueue::new(cpu);
// Create idle task for this CPU
let idle_se = SchedEntity::new(
crate::process::allocate_tid(),
SchedulerPolicy::Idle,
MAX_NICE,
);
rq.idle_task = Some(idle_se);
self.run_queues.push(rq);
}
Ok(())
}
fn add_task(&mut self, tid: Tid, policy: SchedulerPolicy, nice: i32) {
let se = SchedEntity::new(tid, policy, nice);
self.entities.insert(tid, se.clone());
// Add to CPU 0's run queue for simplicity
if let Some(rq) = self.run_queues.get_mut(0) {
rq.enqueue_task(se);
}
}
fn remove_task(&mut self, tid: Tid) {
if let Some(se) = self.entities.remove(&tid) {
// Remove from all run queues
for rq in &mut self.run_queues {
rq.dequeue_task(&se);
}
}
}
fn schedule(&mut self) -> Option<Tid> {
// Simple single-CPU scheduling for now
if let Some(rq) = self.run_queues.get_mut(0) {
rq.update_rq_clock();
if let Some(se) = rq.pick_next_task() {
rq.current = Some(se.clone());
return Some(se.tid);
}
}
None
}
/// Pick next task to run
fn pick_next_task(&mut self) -> Option<Tid> {
// Try CFS first
if let Some(se) = self.cfs.pick_next_task() {
self.current = Some(se.tid);
return Some(se.tid);
}
// Then try RT
if let Some(se) = self.rt.pick_next_task() {
self.current = Some(se.tid);
return Some(se.tid);
}
None
}
/// Switch to a task
fn switch_to(&mut self, tid: Tid) {
// Save current task's context
if let Some(current_tid) = self.current {
if current_tid != tid {
// Look up current and next threads
// We need to use a scope to ensure the lock is dropped before switching
let (current_ctx_ptr, next_ctx_ptr) = {
let mut process_table = PROCESS_TABLE.lock();
let (current_thread, next_thread) = process_table
.find_two_threads_mut(current_tid, tid);
let current_ptr = if let Some(t) = current_thread {
&mut t.context as *mut Context
} else {
return; // Current thread not found?
};
let next_ptr = if let Some(t) = next_thread {
&t.context as *const Context
} else {
return; // Next thread not found
};
(current_ptr, next_ptr)
};
// Update scheduler state
self.current = Some(tid);
self.nr_switches += 1;
// Perform the context switch
// SAFETY: We have valid pointers to the contexts and we've dropped the lock
unsafe {
switch_context(&mut *current_ctx_ptr, &*next_ctx_ptr);
}
return;
}
}
// First task or same task
self.current = Some(tid);
self.nr_switches += 1;
}
/// Set need resched flag
fn set_need_resched(&mut self) {
self.need_resched = true;
}
}
/// Initialize the scheduler
pub fn init() -> Result<()> {
let mut scheduler = SCHEDULER.lock();
scheduler.init()?;
crate::info!("Scheduler initialized with {} CPUs", scheduler.nr_cpus);
Ok(())
}
/// Add a task to the scheduler
pub fn add_task(pid: crate::types::Pid) -> Result<()> {
let mut scheduler = SCHEDULER.lock();
// Create a scheduler entity for the process
let tid = crate::types::Tid(pid.0); // Simple mapping for now
let se = SchedEntity::new(tid, SchedulerPolicy::Normal, DEFAULT_PRIO);
// Add to CFS runqueue
scheduler.cfs.enqueue_task(se);
Ok(())
}
/// Remove a task from the scheduler
pub fn remove_task(pid: crate::types::Pid) -> Result<()> {
let mut scheduler = SCHEDULER.lock();
// Remove from all runqueues
let tid = crate::types::Tid(pid.0);
// Create a minimal SchedEntity for removal
let se = SchedEntity::new(tid, SchedulerPolicy::Normal, DEFAULT_PRIO);
scheduler.cfs.dequeue_task(&se);
scheduler.rt.dequeue_task(&se);
Ok(())
}
/// Schedule next task (called from syscall exit or timer interrupt)
pub fn schedule() {
let mut scheduler = SCHEDULER.lock();
// Pick next task to run
if let Some(next) = scheduler.pick_next_task() {
// Switch to next task
scheduler.switch_to(next);
}
}
/// Get current running task
pub fn current_task() -> Option<crate::types::Pid> {
let scheduler = SCHEDULER.lock();
scheduler.current.map(|tid| crate::types::Pid(tid.0))
}
/// Yield current task (alias for yield_task)
pub fn yield_now() {
yield_task();
}
/// Yield current task
pub fn yield_task() {
let mut scheduler = SCHEDULER.lock();
scheduler.set_need_resched();
}
/// Sleep current task for specified duration
pub fn sleep_task(duration_ms: u64) {
// TODO: implement proper sleep mechanism with timer integration
// For now, just yield
yield_task();
}
/// Wake up a task
pub fn wake_task(pid: crate::types::Pid) -> Result<()> {
let mut scheduler = SCHEDULER.lock();
let tid = crate::types::Tid(pid.0);
// TODO: Move from wait queue to runqueue
// For now, just ensure it's in the runqueue
let se = SchedEntity::new(tid, SchedulerPolicy::Normal, DEFAULT_PRIO);
scheduler.cfs.enqueue_task(se);
Ok(())
}
/// Set task priority
pub fn set_task_priority(pid: crate::types::Pid, priority: i32) -> Result<()> {
let mut scheduler = SCHEDULER.lock();
let tid = crate::types::Tid(pid.0);
// TODO: Update priority in runqueue
// This would require finding the task and updating its priority
Ok(())
}
/// Get scheduler statistics
pub fn get_scheduler_stats() -> SchedulerStats {
let scheduler = SCHEDULER.lock();
SchedulerStats {
total_tasks: (scheduler.cfs.nr_running + scheduler.rt.nr_running) as usize,
running_tasks: if scheduler.current.is_some() { 1 } else { 0 },
context_switches: scheduler.nr_switches,
load_average: scheduler.cfs.load_weight as f64 / 1024.0,
}
}
/// Scheduler statistics
#[derive(Debug, Clone)]
pub struct SchedulerStats {
pub total_tasks: usize,
pub running_tasks: usize,
pub context_switches: u64,
pub load_average: f64,
}
/// Calculate time slice for a task based on its weight
fn calculate_time_slice(se: &SchedEntity) -> u64 {
// Linux-like time slice calculation
let sched_latency = 6_000_000; // 6ms in nanoseconds
let min_granularity = 750_000; // 0.75ms in nanoseconds
// Time slice proportional to weight
let time_slice = sched_latency * se.load_weight as u64 / 1024;
core::cmp::max(time_slice, min_granularity)
}
/// Timer tick - called from timer interrupt
pub fn scheduler_tick() {
SCHEDULE_CLOCK.fetch_add(1, Ordering::Relaxed);
let mut scheduler = SCHEDULER.lock();
// Update current task's runtime
if let Some(rq) = scheduler.run_queues.get_mut(0) {
if let Some(ref mut current) = rq.current {
let now = rq.clock;
let delta = now - current.exec_start;
current.sum_exec_runtime += delta;
current.update_vruntime(delta);
current.exec_start = now;
// Check if we need to reschedule
// For CFS, check if current task has run long enough
if current.policy == SchedulerPolicy::Normal {
let time_slice = calculate_time_slice(current);
if current.sum_exec_runtime - current.prev_sum_exec_runtime
>= time_slice
{
scheduler.set_need_resched();
}
}
}
}
}
/// Perform a manual context switch to a specific task
/// This is used by the enhanced scheduler to execute its scheduling decisions
pub fn context_switch_to(tid: Tid) {
let mut scheduler = SCHEDULER.lock();
scheduler.switch_to(tid);
}

1876
kernel/src/shell.rs Archivo normal

La diferencia del archivo ha sido suprimido porque es demasiado grande Cargar Diff

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

@@ -0,0 +1,278 @@
// SPDX-License-Identifier: GPL-2.0
//! System stress testing and load generation
use alloc::{format, string::String, vec::Vec};
use crate::error::Result;
use crate::time::get_jiffies;
use crate::types::Jiffies;
/// 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
)
}

83
kernel/src/sync.rs Archivo normal
Ver fichero

@@ -0,0 +1,83 @@
// SPDX-License-Identifier: GPL-2.0
//! Synchronization primitives
// Re-export common synchronization types
pub use alloc::sync::Arc;
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::sync::atomic::{AtomicBool, Ordering};
pub use spin::Mutex;
pub use spin::RwLock;
/// Spinlock implementation
pub struct Spinlock<T> {
locked: AtomicBool,
data: UnsafeCell<T>,
}
unsafe impl<T: Send> Sync for Spinlock<T> {}
unsafe impl<T: Send> Send for Spinlock<T> {}
impl<T> Spinlock<T> {
pub const fn new(data: T) -> Self {
Self {
locked: AtomicBool::new(false),
data: UnsafeCell::new(data),
}
}
pub fn lock(&self) -> SpinlockGuard<'_, T> {
while self
.locked
.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
// Busy wait
while self.locked.load(Ordering::Relaxed) {
core::hint::spin_loop();
}
}
SpinlockGuard { lock: self }
}
pub fn try_lock(&self) -> Option<SpinlockGuard<'_, T>> {
if self.locked
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
Some(SpinlockGuard { lock: self })
} else {
None
}
}
}
pub struct SpinlockGuard<'a, T> {
lock: &'a Spinlock<T>,
}
impl<T> Deref for SpinlockGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.lock.data.get() }
}
}
impl<T> DerefMut for SpinlockGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.lock.data.get() }
}
}
impl<T> Drop for SpinlockGuard<'_, T> {
fn drop(&mut self) {
self.lock.locked.store(false, Ordering::Release);
}
}
// Note: We use spin::Mutex and spin::RwLock for actual implementations
// The Spinlock above is for cases where we need a simple spinlock specifically

8
kernel/src/syscall.rs Archivo normal
Ver fichero

@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
//! System call interface
use crate::error::Result;
pub fn init() -> Result<()> {
Ok(())
}

518
kernel/src/syscalls.rs Archivo normal
Ver fichero

@@ -0,0 +1,518 @@
// SPDX-License-Identifier: GPL-2.0
//! System call interface - Linux compatible
use crate::error::{Error, Result};
use crate::process::{allocate_pid, current_process, find_process};
use crate::types::Pid;
/// System call numbers (Linux compatible subset)
#[derive(Debug, Clone, Copy)]
#[repr(u64)]
pub enum SyscallNumber {
Read = 0,
Write = 1,
Open = 2,
Close = 3,
Stat = 4,
Fstat = 5,
Lseek = 8,
Mmap = 9,
Munmap = 11,
Brk = 12,
Ioctl = 16,
Access = 21,
Pipe = 22,
Select = 23,
Socket = 41,
Connect = 42,
Accept = 43,
Fork = 57,
Execve = 59,
Exit = 60,
Wait4 = 61,
Kill = 62,
Getpid = 39,
Getppid = 110,
Getuid = 102,
Setuid = 105,
Getgid = 104,
Setgid = 106,
Gettid = 186,
Clone = 56,
Futex = 202,
}
/// System call arguments structure
#[derive(Debug)]
pub struct SyscallArgs {
pub syscall_num: u64,
pub arg0: u64,
pub arg1: u64,
pub arg2: u64,
pub arg3: u64,
pub arg4: u64,
pub arg5: u64,
}
/// System call dispatcher
pub fn handle_syscall(args: SyscallArgs) -> u64 {
let result = match args.syscall_num {
// Process management
57 => sys_fork(), // fork
59 => sys_execve(args.arg0, args.arg1, args.arg2), // execve
60 => sys_exit(args.arg0 as i32), // exit
61 => sys_wait4(args.arg0, args.arg1, args.arg2, args.arg3), // wait4
62 => sys_kill(args.arg0 as i32, args.arg1 as i32), // kill
// Process info
39 => Ok(sys_getpid() as u64), // getpid
110 => Ok(sys_getppid() as u64), // getppid
102 => Ok(sys_getuid() as u64), // getuid
104 => Ok(sys_getgid() as u64), // getgid
186 => Ok(sys_gettid() as u64), // gettid
// File operations
0 => sys_read(args.arg0 as i32, args.arg1, args.arg2), // read
1 => sys_write(args.arg0 as i32, args.arg1, args.arg2), // write
2 => sys_open(args.arg0, args.arg1 as i32, args.arg2 as u32), // open
3 => sys_close(args.arg0 as i32), // close
// Memory management
9 => sys_mmap(
args.arg0,
args.arg1,
args.arg2 as i32,
args.arg3 as i32,
args.arg4 as i32,
args.arg5 as i64,
), // mmap
11 => sys_munmap(args.arg0, args.arg1), // munmap
12 => sys_brk(args.arg0), // brk
// Unimplemented syscalls
_ => Err(Error::ENOSYS),
};
match result {
Ok(value) => value,
Err(error) => (-error.to_errno()) as u64,
}
}
/// Process management syscalls
pub fn sys_fork() -> Result<u64> {
use crate::process::create_process;
use crate::scheduler::add_task;
// Get current process
let current = current_process().ok_or(Error::ESRCH)?;
// Fork the process
let child = current.fork()?;
let child_pid = child.pid;
// Add child to process table and scheduler
let mut table = crate::process::PROCESS_TABLE.lock();
table.add_process(child.clone());
drop(table);
// Add to scheduler
add_task(child_pid)?;
// Return child PID to parent (in child, this would return 0)
Ok(child_pid.0 as u64)
}
pub fn sys_execve(filename: u64, argv: u64, envp: u64) -> Result<u64> {
use crate::memory::{copy_string_from_user, UserPtr};
// Copy filename from user space
let user_ptr = UserPtr::from_const(filename as *const u8)?;
let filename_str = copy_string_from_user(user_ptr, 256)?;
// Get current process
let mut current = current_process().ok_or(Error::ESRCH)?;
// Execute new program (with empty args for now)
current.exec(&filename_str, alloc::vec![])?;
// This doesn't return on success
Ok(0)
}
pub fn sys_exit(exit_code: i32) -> Result<u64> {
use crate::scheduler::remove_task;
// Get current process
if let Some(mut current) = current_process() {
// Set exit code and mark as zombie
current.exit(exit_code);
// Remove from scheduler
let _ = remove_task(current.pid);
// In a real implementation, this would:
// 1. Free all process resources
// 2. Notify parent process
// 3. Reparent children to init
// 4. Schedule next process
// Signal scheduler to switch to next process
crate::scheduler::schedule();
}
// This syscall doesn't return
loop {
unsafe { core::arch::asm!("hlt") };
}
}
pub fn sys_wait4(pid: u64, status: u64, options: u64, rusage: u64) -> Result<u64> {
use crate::memory::{copy_to_user, UserPtr};
// Get current process
let current = current_process().ok_or(Error::ESRCH)?;
// Wait for child process
let (child_pid, exit_status) = current.wait()?;
// If status pointer is provided, write exit status
if status != 0 {
let status_ptr = UserPtr::new(status as *mut i32)?;
copy_to_user(status_ptr.cast(), &exit_status.to_ne_bytes())?;
}
Ok(child_pid.0 as u64)
}
pub fn sys_kill(pid: i32, signal: i32) -> Result<u64> {
if let Some(mut process) = find_process(Pid(pid as u32)) {
process.send_signal(signal)?;
Ok(0)
} else {
Err(Error::ESRCH)
}
}
/// Process info syscalls
pub fn sys_getpid() -> u32 {
current_process().map(|p| p.pid.0).unwrap_or(0)
}
pub fn sys_getppid() -> u32 {
current_process()
.and_then(|p| p.parent)
.map(|p| p.0)
.unwrap_or(0)
}
pub fn sys_getuid() -> u32 {
current_process().map(|p| p.uid.0).unwrap_or(0)
}
pub fn sys_getgid() -> u32 {
current_process().map(|p| p.gid.0).unwrap_or(0)
}
pub fn sys_gettid() -> u32 {
// For now, return PID (single-threaded processes)
sys_getpid()
}
/// File operation syscalls
pub fn sys_read(fd: i32, buf: u64, count: u64) -> Result<u64> {
use crate::fs::{get_file_descriptor, read_file};
use crate::memory::{copy_to_user, UserPtr};
// Validate parameters
if count == 0 {
return Ok(0);
}
// Get file from file descriptor table
let file = get_file_descriptor(fd).ok_or(Error::EBADF)?;
// Create a kernel buffer to read into
let mut kernel_buf = alloc::vec![0u8; count as usize];
// Read from file
let bytes_read = read_file(&file, &mut kernel_buf)?;
// Copy to user buffer
let user_ptr = UserPtr::new(buf as *mut u8)?;
copy_to_user(user_ptr, &kernel_buf[..bytes_read])?;
Ok(bytes_read as u64)
}
pub fn sys_write(fd: i32, buf: u64, count: u64) -> Result<u64> {
use crate::fs::{get_file_descriptor, write_file};
use crate::memory::{copy_from_user, UserPtr};
// Validate parameters
if count == 0 {
return Ok(0);
}
// Handle stdout/stderr specially for now
if fd == 1 || fd == 2 {
// Create kernel buffer and copy from user
let mut kernel_buf = alloc::vec![0u8; count as usize];
let user_ptr = UserPtr::from_const(buf as *const u8)?;
copy_from_user(&mut kernel_buf, user_ptr)?;
// Write to console (for debugging)
if let Ok(s) = core::str::from_utf8(&kernel_buf) {
crate::print!("{}", s);
}
return Ok(count);
}
// Get file from file descriptor table
let file = get_file_descriptor(fd).ok_or(Error::EBADF)?;
// Create kernel buffer and copy from user
let mut kernel_buf = alloc::vec![0u8; count as usize];
let user_ptr = UserPtr::from_const(buf as *const u8)?;
copy_from_user(&mut kernel_buf, user_ptr)?;
// Write to file
let bytes_written = write_file(&file, &kernel_buf)?;
Ok(bytes_written as u64)
}
pub fn sys_open(filename: u64, flags: i32, mode: u32) -> Result<u64> {
use crate::fs::{allocate_file_descriptor, open_file};
use crate::memory::{copy_string_from_user, UserPtr};
// Copy filename from user space
let user_ptr = UserPtr::from_const(filename as *const u8)?;
let filename_str = copy_string_from_user(user_ptr, 256)?; // Max 256 chars
// Open file in VFS
let file = open_file(&filename_str, flags, mode)?;
// Allocate file descriptor and add to process file table
let fd = allocate_file_descriptor(file)?;
Ok(fd as u64)
}
pub fn sys_close(fd: i32) -> Result<u64> {
use crate::fs::close_file_descriptor;
// Close file descriptor
close_file_descriptor(fd)?;
Ok(0)
}
/// Memory management syscalls
pub fn sys_mmap(
addr: u64,
length: u64,
prot: i32,
flags: i32,
fd: i32,
offset: i64,
) -> Result<u64> {
use crate::memory::{allocate_virtual_memory, VirtAddr, VmaArea};
// Validate parameters
if length == 0 {
return Err(Error::EINVAL);
}
// Align length to page boundary
let page_size = 4096u64;
let aligned_length = (length + page_size - 1) & !(page_size - 1);
// Allocate virtual memory region
let vma = if addr == 0 {
// Let kernel choose address
allocate_virtual_memory(aligned_length, prot as u32, flags as u32)?
} else {
// Use specified address (with validation)
let virt_addr = VirtAddr::new(addr as usize);
// Validate that the address range is available
if !crate::memory::is_virtual_range_free(virt_addr, aligned_length) {
return Err(Error::EEXIST);
}
// Allocate and map the memory
let vma = allocate_virtual_memory(aligned_length, prot as u32, flags as u32)?;
vma
};
// Handle file mapping
if fd >= 0 {
// Map file into memory - simplified implementation
crate::info!("File mapping requested for fd {} at offset {}", fd, offset);
// In a real implementation, this would:
// 1. Get the file descriptor from current process
// 2. Map file pages into the VMA
// 3. Set up page fault handler for demand paging
}
Ok(vma.vm_start.as_usize() as u64)
}
pub fn sys_munmap(addr: u64, length: u64) -> Result<u64> {
use crate::memory::{free_virtual_memory, VirtAddr};
// Validate parameters
if length == 0 {
return Err(Error::EINVAL);
}
// Align to page boundaries
let page_size = 4096u64;
let aligned_addr = addr & !(page_size - 1);
let aligned_length = (length + page_size - 1) & !(page_size - 1);
// Free virtual memory region
free_virtual_memory(VirtAddr::new(aligned_addr as usize), aligned_length)?;
Ok(0)
}
pub fn sys_brk(addr: u64) -> Result<u64> {
use crate::memory::{get_heap_end, set_heap_end, VirtAddr};
// Get current heap end
let current_brk = get_heap_end();
if addr == 0 {
// Return current heap end
return Ok(current_brk.as_usize() as u64);
}
let new_brk = VirtAddr::new(addr as usize);
// Validate new address
if new_brk < current_brk {
// Shrinking heap - free pages
let pages_to_free = (current_brk.as_usize() - new_brk.as_usize() + 4095) / 4096;
crate::info!("Shrinking heap, freeing {} pages", pages_to_free);
// In a real implementation, this would free the actual pages
} else if new_brk > current_brk {
// Expanding heap - allocate pages
let pages_to_alloc = (new_brk.as_usize() - current_brk.as_usize() + 4095) / 4096;
crate::info!("Expanding heap, allocating {} pages", pages_to_alloc);
// In a real implementation, this would allocate and map new
// pages
}
// Update heap end
set_heap_end(new_brk)?;
Ok(new_brk.as_usize() as u64)
}
/// Architecture-specific syscall entry point
#[cfg(target_arch = "x86_64")]
pub mod arch {
use super::*;
/// x86_64 syscall entry point (called from assembly)
#[no_mangle]
pub extern "C" fn syscall_entry(
syscall_num: u64,
arg0: u64,
arg1: u64,
arg2: u64,
arg3: u64,
arg4: u64,
arg5: u64,
) -> u64 {
let args = SyscallArgs {
syscall_num,
arg0,
arg1,
arg2,
arg3,
arg4,
arg5,
};
handle_syscall(args)
}
}
/// Initialize syscall handling
pub fn init_syscalls() -> Result<()> {
// Set up syscall entry point for x86_64
#[cfg(target_arch = "x86_64")]
unsafe {
// Enable SYSCALL/SYSRET instructions
// Set up STAR MSR (syscall target address register)
let star_msr = 0xC0000081u32;
let lstar_msr = 0xC0000082u32;
let sfmask_msr = 0xC0000084u32;
// Set up kernel and user code segments in STAR
// Format: [63:48] user CS, [47:32] kernel CS
let star_value = (0x1Bu64 << 48) | (0x08u64 << 32);
// Write STAR MSR
core::arch::asm!(
"wrmsr",
in("ecx") star_msr,
in("eax") (star_value & 0xFFFFFFFF) as u32,
in("edx") (star_value >> 32) as u32,
options(nostack, preserves_flags)
);
// Set LSTAR to point to our syscall entry
let entry_addr = arch::syscall_entry as *const () as u64;
core::arch::asm!(
"wrmsr",
in("ecx") lstar_msr,
in("eax") (entry_addr & 0xFFFFFFFF) as u32,
in("edx") (entry_addr >> 32) as u32,
options(nostack, preserves_flags)
);
// Set SFMASK to mask interrupt flag during syscall
core::arch::asm!(
"wrmsr",
in("ecx") sfmask_msr,
in("eax") 0x200u32, // Mask IF (interrupt flag)
in("edx") 0u32,
options(nostack, preserves_flags)
);
// Enable SCE (System Call Extensions) in EFER
let efer_msr = 0xC0000080u32;
let mut efer_low: u32;
let mut efer_high: u32;
// Read current EFER
core::arch::asm!(
"rdmsr",
in("ecx") efer_msr,
out("eax") efer_low,
out("edx") efer_high,
options(nostack, preserves_flags)
);
// Set SCE bit (bit 0)
efer_low |= 1;
// Write back EFER
core::arch::asm!(
"wrmsr",
in("ecx") efer_msr,
in("eax") efer_low,
in("edx") efer_high,
options(nostack, preserves_flags)
);
}
crate::info!("Syscall handling initialized");
Ok(())
}

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

@@ -0,0 +1,432 @@
// SPDX-License-Identifier: GPL-2.0
//! System information and hardware detection
use alloc::{format, string::String, vec::Vec};
use crate::error::Result;
use crate::sync::Spinlock;
/// 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:e}, 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:e}, 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
}
}

10
kernel/src/task.rs Archivo normal
Ver fichero

@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
//! Task management
use crate::error::Result;
pub struct Task;
pub fn init() -> Result<()> {
Ok(())
}

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

@@ -0,0 +1,150 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel initialization testing and validation
use crate::error::Result;
use crate::{error, info, warn};
/// 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(())
}

660
kernel/src/test_suite.rs Archivo normal
Ver fichero

@@ -0,0 +1,660 @@
// SPDX-License-Identifier: GPL-2.0
//! Comprehensive kernel test suite
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use crate::error::{Error, Result};
/// Test result structure
#[derive(Debug, Clone)]
pub struct TestResult {
pub name: String,
pub passed: bool,
pub message: String,
pub duration_ms: u64,
}
/// Test suite statistics
#[derive(Debug, Clone)]
pub struct TestStats {
pub total_tests: u32,
pub passed_tests: u32,
pub failed_tests: u32,
pub total_duration_ms: u64,
}
/// Run all kernel tests
pub fn run_all_tests() -> Result<TestStats> {
crate::info!("Starting comprehensive kernel test suite...");
let mut results = Vec::new();
let start_time = crate::time::get_time_ns();
// Memory management tests
results.extend(test_memory_management()?);
// Scheduler tests
results.extend(test_scheduler()?);
// IPC tests
results.extend(test_ipc()?);
// Performance monitoring tests
results.extend(test_performance_monitoring()?);
// File system tests
results.extend(test_filesystem()?);
// Hardware detection tests
results.extend(test_hardware_detection()?);
// Timer tests
results.extend(test_timer_functionality()?);
let end_time = crate::time::get_time_ns();
let total_duration = (end_time - start_time) / 1_000_000; // Convert to ms
// Calculate statistics
let stats = TestStats {
total_tests: results.len() as u32,
passed_tests: results.iter().filter(|r| r.passed).count() as u32,
failed_tests: results.iter().filter(|r| !r.passed).count() as u32,
total_duration_ms: total_duration,
};
// Print results summary
print_test_summary(&results, &stats);
Ok(stats)
}
/// Test memory management functionality
fn test_memory_management() -> Result<Vec<TestResult>> {
let mut results = Vec::new();
// Test basic allocation
results.push(test_basic_allocation());
// Test advanced allocator stats
results.push(test_allocator_stats());
// Test heap operations
results.push(test_heap_operations());
Ok(results)
}
/// Test basic memory allocation
fn test_basic_allocation() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
// Test kmalloc
let ptr = crate::memory::kmalloc::kmalloc(1024)?;
if ptr.is_null() {
return Err(crate::error::Error::ENOMEM);
}
// Test writing to allocated memory
unsafe {
core::ptr::write(ptr, 42u8);
let value = core::ptr::read(ptr);
if value != 42 {
return Err(crate::error::Error::EIO);
}
}
// Free memory
crate::memory::kmalloc::kfree(ptr);
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "Basic Memory Allocation".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"Failed".to_string()
},
duration_ms: duration,
}
}
/// Test allocator statistics
fn test_allocator_stats() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
let stats = crate::memory::advanced_allocator::get_memory_stats();
// Basic sanity checks
if stats.allocation_count < stats.active_allocations as u64 {
return Err(crate::error::Error::EIO);
}
if stats.peak_usage < stats.current_allocated {
return Err(crate::error::Error::EIO);
}
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "Allocator Statistics".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"Stats validation failed".to_string()
},
duration_ms: duration,
}
}
/// Test heap operations
fn test_heap_operations() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
let initial_heap = crate::memory::get_heap_end();
let new_heap = crate::types::VirtAddr::new(initial_heap.as_usize() + 4096);
// Test heap expansion
crate::memory::set_heap_end(new_heap)?;
let current_heap = crate::memory::get_heap_end();
if current_heap != new_heap {
return Err(crate::error::Error::EIO);
}
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "Heap Operations".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"Heap operations failed".to_string()
},
duration_ms: duration,
}
}
/// Test scheduler functionality
fn test_scheduler() -> Result<Vec<TestResult>> {
let mut results = Vec::new();
results.push(test_scheduler_stats());
results.push(test_task_creation());
Ok(results)
}
/// Test scheduler statistics
fn test_scheduler_stats() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
let stats = crate::enhanced_scheduler::get_scheduler_stats();
// Basic validation
if stats.total_tasks < stats.runnable_tasks {
return Err(crate::error::Error::EIO);
}
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "Scheduler Statistics".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"Scheduler stats invalid".to_string()
},
duration_ms: duration,
}
}
/// Test task creation
fn test_task_creation() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
let initial_count = crate::working_task::get_task_count();
// Create a test task
let _task_id =
crate::working_task::create_kernel_task("test_task", test_task_function)?;
let new_count = crate::working_task::get_task_count();
if new_count <= initial_count {
return Err(crate::error::Error::EIO);
}
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "Task Creation".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"Task creation failed".to_string()
},
duration_ms: duration,
}
}
/// Test IPC functionality
fn test_ipc() -> Result<Vec<TestResult>> {
let mut results = Vec::new();
results.push(test_ipc_stats());
results.push(test_message_queue());
Ok(results)
}
/// Test IPC statistics
fn test_ipc_stats() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
let stats = crate::ipc::get_ipc_stats();
// Basic validation - stats should be consistent
if stats.messages_sent < stats.messages_received && stats.messages_received > 0 {
return Err(crate::error::Error::EIO);
}
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "IPC Statistics".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"IPC stats invalid".to_string()
},
duration_ms: duration,
}
}
/// Test message queue operations
fn test_message_queue() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
// Create a message queue (simplified test)
let test_tid = crate::types::Tid(1);
let _queue_result = crate::ipc::create_message_queue(test_tid, 1024);
// Send a test message
let test_data = b"Hello, IPC!";
let sender_tid = crate::types::Tid(1);
let recipient_tid = crate::types::Tid(2);
let message_type = crate::ipc::MessageType::Data;
let data_vec = test_data.to_vec();
let _send_result = crate::ipc::send_message(
sender_tid,
recipient_tid,
message_type,
data_vec,
1,
);
// Try to receive the message
if let Ok(Some(_message)) = crate::ipc::receive_message(test_tid) {
Ok(())
} else {
Err(crate::error::Error::EIO)
}
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "Message Queue Operations".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"Message queue test failed".to_string()
},
duration_ms: duration,
}
}
/// Test performance monitoring
fn test_performance_monitoring() -> Result<Vec<TestResult>> {
let mut results = Vec::new();
results.push(test_perf_counters());
results.push(test_profiling());
Ok(results)
}
/// Test performance counters
fn test_perf_counters() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
let summary = crate::advanced_perf::get_performance_summary();
// Check if monitoring is enabled
if !summary.monitoring_enabled {
return Err(crate::error::Error::EIO);
}
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "Performance Counters".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"Performance monitoring disabled".to_string()
},
duration_ms: duration,
}
}
/// Test profiling functionality
fn test_profiling() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
// Start profiling for a test function
let _guard = crate::advanced_perf::profile_function("test_function");
// Do some work
for _i in 0..1000 {
unsafe { core::arch::asm!("nop") };
}
// Guard should automatically stop profiling when dropped
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "Function Profiling".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"Profiling failed".to_string()
},
duration_ms: duration,
}
}
/// Test file system functionality
fn test_filesystem() -> Result<Vec<TestResult>> {
let mut results = Vec::new();
results.push(test_fs_basic_ops());
Ok(results)
}
/// Test basic file system operations
fn test_fs_basic_ops() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
// Test VFS initialization
let _vfs = crate::fs::get_root_fs()?;
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "File System Basic Operations".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"VFS operations failed".to_string()
},
duration_ms: duration,
}
}
/// Test hardware detection
fn test_hardware_detection() -> Result<Vec<TestResult>> {
let mut results = Vec::new();
results.push(test_cpu_detection());
results.push(test_memory_detection());
Ok(results)
}
/// Test CPU detection
fn test_cpu_detection() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
let cpu_info = crate::hardware::detect_cpu()?;
if cpu_info.vendor.is_empty() {
return Err(crate::error::Error::EIO);
}
if cpu_info.core_count == 0 {
return Err(crate::error::Error::EIO);
}
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "CPU Detection".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"CPU detection failed".to_string()
},
duration_ms: duration,
}
}
/// Test memory detection
fn test_memory_detection() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
let memory_size = crate::hardware::detect_memory()?;
if memory_size < 16 * 1024 * 1024 {
// Less than 16MB seems wrong
return Err(crate::error::Error::EIO);
}
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "Memory Detection".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"Memory detection failed".to_string()
},
duration_ms: duration,
}
}
/// Test timer functionality
fn test_timer_functionality() -> Result<Vec<TestResult>> {
let mut results = Vec::new();
results.push(test_timer_basic());
results.push(test_jiffies());
Ok(results)
}
/// Test basic timer functionality
fn test_timer_basic() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
let time1 = crate::time::get_time_ns();
// Do some work
for _i in 0..100 {
unsafe { core::arch::asm!("nop") };
}
let time2 = crate::time::get_time_ns();
if time2 <= time1 {
return Err(crate::error::Error::EIO);
}
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "Timer Basic Functionality".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"Timer not working".to_string()
},
duration_ms: duration,
}
}
/// Test jiffies counter
fn test_jiffies() -> TestResult {
let start = crate::time::get_time_ns();
let result = || -> Result<()> {
let jiffies1 = crate::time::get_jiffies();
// Wait a bit (simulate time passing)
for _i in 0..1000 {
unsafe { core::arch::asm!("nop") };
}
let jiffies2 = crate::time::get_jiffies();
// Jiffies should either be the same or have incremented
if jiffies2.0 < jiffies1.0 {
return Err(crate::error::Error::EIO);
}
Ok(())
}();
let end = crate::time::get_time_ns();
let duration = (end - start) / 1_000_000;
TestResult {
name: "Jiffies Counter".to_string(),
passed: result.is_ok(),
message: if result.is_ok() {
"Passed".to_string()
} else {
"Jiffies counter broken".to_string()
},
duration_ms: duration,
}
}
/// Test task function for task creation test
fn test_task_function() {
// Simple test task that does nothing
crate::info!("Test task executing");
}
/// Print test results summary
fn print_test_summary(results: &[TestResult], stats: &TestStats) {
crate::info!("=== KERNEL TEST SUITE RESULTS ===");
crate::info!("Total tests: {}", stats.total_tests);
crate::info!("Passed: {}", stats.passed_tests);
crate::info!("Failed: {}", stats.failed_tests);
crate::info!(
"Success rate: {:.1}%",
(stats.passed_tests as f32 / stats.total_tests as f32) * 100.0
);
crate::info!("Total duration: {} ms", stats.total_duration_ms);
if stats.failed_tests > 0 {
crate::info!("Failed tests:");
for result in results {
if !result.passed {
crate::info!(
" - {} ({}ms): {}",
result.name,
result.duration_ms,
result.message
);
}
}
}
crate::info!("=== END TEST RESULTS ===");
}
/// Initialize test suite
pub fn init() -> Result<()> {
crate::info!("Kernel test suite initialized");
Ok(())
}

507
kernel/src/time.rs Archivo normal
Ver fichero

@@ -0,0 +1,507 @@
// SPDX-License-Identifier: GPL-2.0
//! Time management compatible with Linux kernel
use alloc::vec::Vec;
use core::sync::atomic::{AtomicU64, Ordering};
use crate::error::Result;
use crate::types::Jiffies; // Add Vec import
/// System clock frequency (Hz) - typically 1000 for 1ms ticks
pub const HZ: u64 = 1000;
/// Nanoseconds per second
pub const NSEC_PER_SEC: u64 = 1_000_000_000;
/// Nanoseconds per millisecond
pub const NSEC_PER_MSEC: u64 = 1_000_000;
/// Nanoseconds per microsecond
pub const NSEC_PER_USEC: u64 = 1_000;
/// Nanoseconds per jiffy
pub const NSEC_PER_JIFFY: u64 = NSEC_PER_SEC / HZ;
/// Global time counters
static JIFFIES_COUNTER: AtomicU64 = AtomicU64::new(0);
static BOOTTIME_NS: AtomicU64 = AtomicU64::new(0);
/// TSC (Time Stamp Counter) related globals
pub static TSC_FREQUENCY: AtomicU64 = AtomicU64::new(0);
static BOOT_TSC: AtomicU64 = AtomicU64::new(0);
/// Time structure - Linux compatible
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct TimeSpec {
pub tv_sec: i64,
pub tv_nsec: i64,
}
impl TimeSpec {
pub const fn new(sec: i64, nsec: i64) -> Self {
Self {
tv_sec: sec,
tv_nsec: nsec,
}
}
pub fn zero() -> Self {
Self::new(0, 0)
}
pub fn to_ns(&self) -> u64 {
(self.tv_sec as u64 * NSEC_PER_SEC) + self.tv_nsec as u64
}
pub fn from_ns(ns: u64) -> Self {
let sec = (ns / NSEC_PER_SEC) as i64;
let nsec = (ns % NSEC_PER_SEC) as i64;
Self::new(sec, nsec)
}
}
/// Get current system time
pub fn get_current_time() -> TimeSpec {
// In a real implementation, this would read from a real-time clock
// For now, we'll use the boot time plus jiffies
let boot_ns = BOOTTIME_NS.load(Ordering::Relaxed);
let jiffies = get_jiffies();
let current_ns = boot_ns + (jiffies * NSEC_PER_JIFFY);
TimeSpec::from_ns(current_ns)
}
/// High resolution timer structure
#[derive(Debug, Clone)]
pub struct HrTimer {
pub expires: TimeSpec,
pub function: Option<fn()>,
pub base: HrTimerBase,
}
/// Timer bases - Linux compatible
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HrTimerBase {
Monotonic,
Realtime,
Boottime,
Tai,
}
impl HrTimer {
pub fn new(base: HrTimerBase) -> Self {
Self {
expires: TimeSpec::zero(),
function: None,
base,
}
}
pub fn set_expires(&mut self, expires: TimeSpec) {
self.expires = expires;
}
pub fn set_function(&mut self, function: fn()) {
self.function = Some(function);
}
pub fn is_expired(&self) -> bool {
let now = match self.base {
HrTimerBase::Monotonic => monotonic_time(),
HrTimerBase::Realtime => get_realtime(),
HrTimerBase::Boottime => get_boottime(),
HrTimerBase::Tai => get_realtime(), // Simplified
};
now >= self.expires
}
}
/// Initialize time management
pub fn init() -> Result<()> {
// Initialize system clocks
let boot_time = read_hardware_clock();
BOOTTIME_NS.store(boot_time, Ordering::Relaxed);
// Set up timer interrupts through our timer module
crate::timer::init_timer()?;
// Initialize high-resolution timers
init_high_res_timers()?;
crate::info!("Time management initialized, boot time: {} ns", boot_time);
Ok(())
}
/// Initialize high-resolution timers
fn init_high_res_timers() -> Result<()> {
// Initialize TSC (Time Stamp Counter) frequency detection
let tsc_freq = detect_tsc_frequency();
TSC_FREQUENCY.store(tsc_freq, Ordering::Relaxed);
// Store initial TSC value for relative timing
BOOT_TSC.store(read_tsc(), Ordering::Relaxed);
crate::info!(
"High-resolution timers initialized, TSC frequency: {} Hz",
tsc_freq
);
Ok(())
}
/// Detect TSC frequency using PIT calibration
fn detect_tsc_frequency() -> u64 {
// Calibrate TSC against PIT (Programmable Interval Timer)
// This is a simplified implementation
unsafe {
// Set PIT to mode 2 (rate generator) with a known frequency
crate::arch::x86_64::port::outb(0x43, 0x34); // Channel 0, mode 2
// Set frequency to ~1193 Hz (divisor = 1000)
let divisor = 1000u16;
crate::arch::x86_64::port::outb(0x40, (divisor & 0xFF) as u8);
crate::arch::x86_64::port::outb(0x40, (divisor >> 8) as u8);
// Read initial TSC
let tsc_start = read_tsc();
// Wait for a PIT tick (simplified timing)
let mut last_pit = read_pit_count();
let mut pit_ticks = 0;
while pit_ticks < 10 {
// Wait for ~10ms
let current_pit = read_pit_count();
if current_pit != last_pit {
pit_ticks += 1;
last_pit = current_pit;
}
}
// Read final TSC
let tsc_end = read_tsc();
let tsc_delta = tsc_end - tsc_start;
// Calculate frequency (rough approximation)
// 10 PIT ticks at ~1193 Hz = ~8.4ms
let frequency = (tsc_delta * 1193) / 10;
// Reasonable bounds checking
if frequency < 100_000_000 || frequency > 10_000_000_000 {
// Default to 2.4 GHz if calibration seems wrong
2_400_000_000
} else {
frequency
}
}
}
/// Read PIT counter value
unsafe fn read_pit_count() -> u16 {
crate::arch::x86_64::port::outb(0x43, 0x00); // Latch counter 0
let low = crate::arch::x86_64::port::inb(0x40) as u16;
let high = crate::arch::x86_64::port::inb(0x40) as u16;
(high << 8) | low
}
/// Initialize time management subsystem
pub fn init_time() -> Result<()> {
// Initialize the timer wheel
let _timer_wheel = get_timer_wheel();
// Set initial boot time (in a real implementation, this would read from RTC)
BOOTTIME_NS.store(0, Ordering::Relaxed);
// Reset jiffies counter
JIFFIES_COUNTER.store(0, Ordering::Relaxed);
crate::info!("Time management initialized");
Ok(())
}
/// Read hardware clock implementation
fn read_hardware_clock() -> u64 {
// Read from CMOS RTC (Real Time Clock)
// This is a simplified implementation
unsafe {
// Disable NMI and read seconds
crate::arch::x86_64::port::outb(0x70, 0x00);
let seconds = crate::arch::x86_64::port::inb(0x71);
// Read minutes
crate::arch::x86_64::port::outb(0x70, 0x02);
let minutes = crate::arch::x86_64::port::inb(0x71);
// Read hours
crate::arch::x86_64::port::outb(0x70, 0x04);
let hours = crate::arch::x86_64::port::inb(0x71);
// Convert BCD to binary if needed (simplified)
let sec = bcd_to_bin(seconds);
let min = bcd_to_bin(minutes);
let hr = bcd_to_bin(hours);
// Convert to nanoseconds since epoch (simplified calculation)
let total_seconds = (hr as u64 * 3600) + (min as u64 * 60) + sec as u64;
total_seconds * 1_000_000_000 // Convert to nanoseconds
}
}
/// Convert BCD to binary
fn bcd_to_bin(bcd: u8) -> u8 {
((bcd >> 4) * 10) + (bcd & 0x0F)
}
/// Get current jiffies count
pub fn get_jiffies() -> Jiffies {
Jiffies(JIFFIES_COUNTER.load(Ordering::Relaxed))
}
/// Increment jiffies counter (called from timer interrupt)
pub fn update_jiffies() {
JIFFIES_COUNTER.fetch_add(1, Ordering::Relaxed);
}
/// Get current time in nanoseconds since boot
pub fn get_time_ns() -> u64 {
// Use TSC for high-resolution timing
let tsc_freq = TSC_FREQUENCY.load(Ordering::Relaxed);
if tsc_freq > 0 {
let tsc = read_tsc();
let boot_tsc = BOOT_TSC.load(Ordering::Relaxed);
if tsc >= boot_tsc {
((tsc - boot_tsc) * 1_000_000_000) / tsc_freq
} else {
// Handle TSC overflow (rare)
get_jiffies().0 * NSEC_PER_JIFFY
}
} else {
// Fallback to jiffies-based timing
get_jiffies().0 * NSEC_PER_JIFFY
}
}
/// Get high resolution time
pub fn ktime_get() -> TimeSpec {
let ns = get_time_ns();
TimeSpec {
tv_sec: (ns / 1_000_000_000) as i64,
tv_nsec: (ns % 1_000_000_000) as i64,
}
}
/// Read Time Stamp Counter
fn read_tsc() -> u64 {
unsafe {
let low: u32;
let high: u32;
core::arch::asm!(
"rdtsc",
out("eax") low,
out("edx") high,
options(nomem, nostack, preserves_flags)
);
((high as u64) << 32) | (low as u64)
}
}
/// Get monotonic time (time since boot)
pub fn monotonic_time() -> TimeSpec {
let jiffies = get_jiffies();
let ns = jiffies.0 * NSEC_PER_JIFFY;
TimeSpec::from_ns(ns)
}
/// Get boot time
pub fn get_boottime() -> TimeSpec {
let boot_ns = BOOTTIME_NS.load(Ordering::Relaxed);
let current_ns = get_time_ns();
TimeSpec::from_ns(boot_ns + current_ns)
}
/// Get real time (wall clock time)
pub fn get_realtime() -> TimeSpec {
get_boottime()
}
/// Convert nanoseconds to jiffies
pub fn ns_to_jiffies(ns: u64) -> Jiffies {
Jiffies(ns / NSEC_PER_JIFFY)
}
/// Convert jiffies to nanoseconds
pub fn jiffies_to_ns(jiffies: Jiffies) -> u64 {
jiffies.0 * NSEC_PER_JIFFY
}
/// Convert milliseconds to jiffies
pub fn msecs_to_jiffies(ms: u64) -> Jiffies {
ns_to_jiffies(ms * NSEC_PER_MSEC)
}
/// Convert jiffies to milliseconds
pub fn jiffies_to_msecs(jiffies: Jiffies) -> u64 {
jiffies_to_ns(jiffies) / NSEC_PER_MSEC
}
/// Convert microseconds to jiffies
pub fn usecs_to_jiffies(us: u64) -> Jiffies {
ns_to_jiffies(us * NSEC_PER_USEC)
}
/// Convert jiffies to microseconds
pub fn jiffies_to_usecs(jiffies: Jiffies) -> u64 {
jiffies_to_ns(jiffies) / NSEC_PER_USEC
}
/// Sleep functions - Linux compatible
pub fn msleep(ms: u64) {
let target_jiffies = get_jiffies().0 + msecs_to_jiffies(ms).0;
while get_jiffies().0 < target_jiffies {
crate::scheduler::yield_now();
}
}
pub fn usleep_range(min_us: u64, max_us: u64) {
let us = (min_us + max_us) / 2; // Use average
let target_jiffies = get_jiffies().0 + usecs_to_jiffies(us).0;
while get_jiffies().0 < target_jiffies {
crate::scheduler::yield_now();
}
}
pub fn ndelay(ns: u64) {
// Busy wait for nanoseconds (not recommended for long delays)
let start = get_time_ns();
while get_time_ns() - start < ns {
core::hint::spin_loop();
}
}
pub fn udelay(us: u64) {
ndelay(us * NSEC_PER_USEC);
}
pub fn mdelay(ms: u64) {
ndelay(ms * NSEC_PER_MSEC);
}
/// Timer wheel for managing timers
#[derive(Debug)]
pub struct TimerWheel {
levels: [Vec<HrTimer>; 8], // Multiple levels for different time ranges
current_jiffies: u64,
}
impl TimerWheel {
pub fn new() -> Self {
const EMPTY_VEC: Vec<HrTimer> = Vec::new();
Self {
levels: [EMPTY_VEC; 8],
current_jiffies: 0,
}
}
pub fn add_timer(&mut self, timer: HrTimer) {
let now_ns = get_time_ns();
let expires_ns = timer.expires.to_ns();
// If already expired or expires very soon, put in level 0
if expires_ns <= now_ns {
self.levels[0].push(timer);
return;
}
let delta_ns = expires_ns - now_ns;
let delta_jiffies = delta_ns / NSEC_PER_JIFFY;
// Determine level based on delta
// Level 0: Immediate to ~256ms
// Level 1: ~256ms to ~16s
// Level 2: ~16s to ~17m
// Level 3: ~17m to ~18h
// Level 4+: Far future
let level = if delta_jiffies < 256 {
0
} else if delta_jiffies < 256 * 64 {
1
} else if delta_jiffies < 256 * 64 * 64 {
2
} else if delta_jiffies < 256 * 64 * 64 * 64 {
3
} else {
4
};
let level = core::cmp::min(level, 7);
self.levels[level].push(timer);
}
pub fn run_timers(&mut self) {
self.current_jiffies = get_jiffies().0;
// Check and run expired timers
for level in &mut self.levels {
level.retain(|timer| {
if timer.is_expired() {
if let Some(function) = timer.function {
function();
}
false // Remove expired timer
} else {
true // Keep timer
}
});
}
}
}
use core::sync::atomic::AtomicBool;
/// Global timer wheel
use crate::sync::Spinlock;
static TIMER_WHEEL_INIT: AtomicBool = AtomicBool::new(false);
static mut TIMER_WHEEL_STORAGE: Option<Spinlock<TimerWheel>> = None;
fn get_timer_wheel() -> &'static Spinlock<TimerWheel> {
if !TIMER_WHEEL_INIT.load(Ordering::Acquire) {
// Initialize timer wheel
let wheel = TimerWheel::new();
unsafe {
TIMER_WHEEL_STORAGE = Some(Spinlock::new(wheel));
}
TIMER_WHEEL_INIT.store(true, Ordering::Release);
}
#[allow(static_mut_refs)]
unsafe {
TIMER_WHEEL_STORAGE.as_ref().unwrap()
}
}
/// Add a timer to the system
pub fn add_timer(timer: HrTimer) {
let timer_wheel = get_timer_wheel();
let mut wheel = timer_wheel.lock();
wheel.add_timer(timer);
}
/// Run expired timers (called from timer interrupt)
pub fn run_timers() {
let timer_wheel = get_timer_wheel();
let mut wheel = timer_wheel.lock();
wheel.run_timers();
}
/// Timer interrupt handler
pub fn timer_interrupt() {
// Update jiffies
update_jiffies();
// Run expired timers
run_timers();
// Update scheduler tick
crate::scheduler::scheduler_tick();
}

251
kernel/src/timer.rs Archivo normal
Ver fichero

@@ -0,0 +1,251 @@
// SPDX-License-Identifier: GPL-2.0
//! Timer interrupt handler for preemptive scheduling
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use crate::enhanced_scheduler;
use crate::sync::Spinlock;
use crate::time::get_jiffies;
use crate::types::Jiffies;
/// Timer frequency (Hz) - how often timer interrupt fires
const TIMER_FREQUENCY: u64 = 1000; // 1000 Hz = 1ms intervals
/// Scheduler quantum (time slice) in timer ticks
const SCHEDULER_QUANTUM: u64 = 10; // 10ms default quantum
/// Timer statistics
#[derive(Debug, Clone)]
pub struct TimerStats {
pub total_interrupts: u64,
pub scheduler_invocations: u64,
pub context_switches: u64,
pub last_update: Jiffies,
}
/// Global timer state
pub struct TimerState {
tick_count: AtomicU64,
last_schedule_tick: AtomicU64,
preemption_enabled: AtomicBool,
stats: Spinlock<TimerStats>,
}
impl TimerState {
const fn new() -> Self {
Self {
tick_count: AtomicU64::new(0),
last_schedule_tick: AtomicU64::new(0),
preemption_enabled: AtomicBool::new(true),
stats: Spinlock::new(TimerStats {
total_interrupts: 0,
scheduler_invocations: 0,
context_switches: 0,
last_update: Jiffies(0),
}),
}
}
/// Handle timer interrupt
pub fn handle_timer_interrupt(&self) {
let current_tick = self.tick_count.fetch_add(1, Ordering::SeqCst);
let last_schedule = self.last_schedule_tick.load(Ordering::SeqCst);
// Update statistics
{
let mut stats = self.stats.lock();
stats.total_interrupts += 1;
stats.last_update = get_jiffies();
}
// Check if we should invoke the scheduler
if self.preemption_enabled.load(Ordering::SeqCst) {
let ticks_since_schedule = current_tick - last_schedule;
if ticks_since_schedule >= SCHEDULER_QUANTUM {
self.invoke_scheduler();
self.last_schedule_tick
.store(current_tick, Ordering::SeqCst);
}
}
// Update current task runtime
enhanced_scheduler::update_current_task_runtime(1);
}
/// Invoke the scheduler for preemptive multitasking
fn invoke_scheduler(&self) {
// Update statistics
{
let mut stats = self.stats.lock();
stats.scheduler_invocations += 1;
}
// Get next task to run
if let Some(next_tid) = enhanced_scheduler::schedule_next() {
let current_tid = enhanced_scheduler::get_current_task();
// Only switch if different task
if current_tid != Some(next_tid) {
if let Ok(()) = enhanced_scheduler::switch_to_task(next_tid) {
// Update context switch statistics
let mut stats = self.stats.lock();
stats.context_switches += 1;
// Perform actual context switch
// This will save current CPU state and restore the state of the next task
crate::scheduler::context_switch_to(next_tid);
crate::info!(
"Context switch: {:?} -> {:?}",
current_tid,
next_tid
);
}
}
}
}
/// Enable or disable preemption
pub fn set_preemption_enabled(&self, enabled: bool) {
self.preemption_enabled.store(enabled, Ordering::SeqCst);
enhanced_scheduler::set_preemption_enabled(enabled);
}
/// Get timer statistics
pub fn get_stats(&self) -> TimerStats {
self.stats.lock().clone()
}
/// Get current tick count
pub fn get_tick_count(&self) -> u64 {
self.tick_count.load(Ordering::SeqCst)
}
/// Reset statistics
pub fn reset_stats(&self) {
let mut stats = self.stats.lock();
stats.total_interrupts = 0;
stats.scheduler_invocations = 0;
stats.context_switches = 0;
stats.last_update = get_jiffies();
}
/// Check if preemption is enabled
pub fn is_preemption_enabled(&self) -> bool {
self.preemption_enabled.load(Ordering::SeqCst)
}
}
/// Timer interrupt counter
static TIMER_INTERRUPTS: AtomicU64 = AtomicU64::new(0);
/// Get timer interrupt count
pub fn get_timer_interrupts() -> u64 {
TIMER_INTERRUPTS.load(Ordering::Relaxed)
}
/// Increment timer interrupt counter
pub fn increment_timer_interrupts() {
TIMER_INTERRUPTS.fetch_add(1, Ordering::Relaxed);
}
/// Global timer state
static TIMER_STATE: TimerState = TimerState::new();
/// Initialize timer for preemptive scheduling
pub fn init_timer() -> crate::error::Result<()> {
// Initialize the Programmable Interval Timer (PIT)
init_pit(TIMER_FREQUENCY)?;
// Enable timer interrupts
crate::arch::x86_64::idt::register_timer_handler(timer_interrupt_handler);
crate::info!(
"Timer initialized for preemptive scheduling ({}Hz)",
TIMER_FREQUENCY
);
Ok(())
}
/// Timer interrupt handler (called from IDT)
pub extern "C" fn timer_interrupt_handler() {
TIMER_STATE.handle_timer_interrupt();
increment_timer_interrupts();
// Send EOI to PIC
unsafe {
crate::arch::x86_64::pic::send_eoi(0); // Timer is IRQ 0
}
}
/// Initialize Programmable Interval Timer (PIT)
fn init_pit(frequency: u64) -> crate::error::Result<()> {
use crate::arch::x86_64::port::Port;
// PIT frequency is 1.193182 MHz
const PIT_FREQUENCY: u64 = 1193182;
// Calculate divisor for desired frequency
let divisor = PIT_FREQUENCY / frequency;
if divisor > 65535 {
return Err(crate::error::Error::InvalidArgument);
}
unsafe {
// Configure PIT channel 0 for periodic mode
let mut cmd_port = Port::new(0x43);
let mut data_port = Port::new(0x40);
// Command: Channel 0, Access mode lobyte/hibyte, Mode 2 (rate generator)
cmd_port.write(0x34u32);
// Set divisor (low byte first, then high byte)
data_port.write((divisor & 0xFF) as u32);
data_port.write((divisor >> 8) as u32);
}
Ok(())
}
/// Get timer statistics
pub fn get_timer_stats() -> TimerStats {
TIMER_STATE.get_stats()
}
/// Enable/disable preemptive scheduling
pub fn set_preemption_enabled(enabled: bool) {
TIMER_STATE.set_preemption_enabled(enabled);
}
/// Get current timer tick count
pub fn get_timer_ticks() -> u64 {
TIMER_STATE.get_tick_count()
}
/// Reset timer statistics
pub fn reset_timer_stats() {
TIMER_STATE.reset_stats();
}
/// Sleep for specified number of timer ticks
pub fn sleep_ticks(ticks: u64) -> crate::error::Result<()> {
enhanced_scheduler::sleep_current_task(ticks)
}
/// Yield current task to scheduler
pub fn yield_task() {
TIMER_STATE.invoke_scheduler();
}
/// Handle timer tick - called from kernel loops for timing updates
pub fn handle_timer_tick() {
// Update timer statistics
TIMER_STATE.handle_timer_interrupt();
// Trigger scheduler if preemption is enabled
if TIMER_STATE.is_preemption_enabled() {
yield_task();
}
}

206
kernel/src/types.rs Archivo normal
Ver fichero

@@ -0,0 +1,206 @@
// SPDX-License-Identifier: GPL-2.0
//! Common kernel types
use core::fmt;
use core::ops::{Add, Mul, Sub};
/// Process ID type
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Pid(pub u32);
impl fmt::Display for Pid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
/// Thread ID type
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Tid(pub u32);
impl fmt::Display for Tid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
/// User ID type
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Uid(pub u32);
/// Group ID type
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Gid(pub u32);
/// Physical address type
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PhysAddr(pub usize);
impl PhysAddr {
pub const fn new(addr: usize) -> Self {
Self(addr)
}
pub const fn as_u64(self) -> u64 {
self.0 as u64
}
pub const fn as_usize(self) -> usize {
self.0
}
}
impl Add<usize> for PhysAddr {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self(self.0 + rhs)
}
}
impl Sub<usize> for PhysAddr {
type Output = Self;
fn sub(self, rhs: usize) -> Self::Output {
Self(self.0 - rhs)
}
}
/// Virtual address type
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct VirtAddr(pub usize);
impl VirtAddr {
pub const fn new(addr: usize) -> Self {
Self(addr)
}
pub const fn as_u64(self) -> u64 {
self.0 as u64
}
pub const fn as_usize(self) -> usize {
self.0
}
pub const fn as_ptr<T>(self) -> *const T {
self.0 as *const T
}
pub const fn as_mut_ptr<T>(self) -> *mut T {
self.0 as *mut T
}
}
impl Add<usize> for VirtAddr {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self(self.0 + rhs)
}
}
impl Sub<usize> for VirtAddr {
type Output = Self;
fn sub(self, rhs: usize) -> Self::Output {
Self(self.0 - rhs)
}
}
impl Sub<VirtAddr> for VirtAddr {
type Output = usize;
fn sub(self, rhs: VirtAddr) -> Self::Output {
self.0 - rhs.0
}
}
impl fmt::Display for VirtAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "0x{:x}", self.0)
}
}
/// Page size constants
pub const PAGE_SIZE: usize = 4096;
pub const PAGE_SHIFT: usize = 12;
/// Page frame number
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Pfn(pub usize);
impl Pfn {
pub fn from_phys_addr(addr: PhysAddr) -> Self {
Self(addr.0 >> PAGE_SHIFT)
}
pub fn to_phys_addr(self) -> PhysAddr {
PhysAddr(self.0 << PAGE_SHIFT)
}
}
/// CPU number type
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct CpuId(pub u32);
/// IRQ number type
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Irq(pub u32);
/// Time types
#[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;
fn mul(self, rhs: u64) -> Self::Output {
self.0 * rhs
}
}
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);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Microseconds(pub u64);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Milliseconds(pub u64);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Seconds(pub u64);
/// Device ID type
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId(pub u32);
impl fmt::Display for DeviceId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}

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

@@ -0,0 +1,368 @@
// SPDX-License-Identifier: GPL-2.0
//! User mode program support
use alloc::{boxed::Box, string::String, vec, vec::Vec};
use crate::arch::x86_64::context::Context;
use crate::error::{Error, Result};
use crate::memory::{PageFlags, PhysAddr, VirtAddr};
use crate::process::{Process, ProcessState, Thread};
use crate::types::{Gid, Uid};
/// 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())
}

345
kernel/src/working_task.rs Archivo normal
Ver fichero

@@ -0,0 +1,345 @@
// SPDX-License-Identifier: GPL-2.0
//! Working kernel task implementation with actual functionality
use alloc::{
boxed::Box,
format,
string::{String, ToString},
vec::Vec,
};
use core::sync::atomic::{AtomicU32, Ordering};
use crate::arch::x86_64::context::Context;
use crate::error::{Error, Result};
use crate::memory::kmalloc;
use crate::sync::Spinlock;
use crate::types::{Pid, Tid};
/// Task function type
pub type TaskFunction = fn() -> ();
/// Task state
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TaskState {
Running,
Ready,
Blocked,
Terminated,
}
/// Working task structure
#[derive(Debug, Clone)]
pub struct Task {
pub tid: Tid,
pub pid: Pid,
pub name: String,
pub state: TaskState,
pub context: Context,
pub stack_base: usize,
pub stack_size: usize,
pub priority: u8,
pub cpu_time: u64,
pub creation_time: u64,
}
impl Task {
/// Create a new kernel task
pub fn new_kernel_task(
name: String,
function: TaskFunction,
stack_size: usize,
) -> Result<Self> {
// Use process subsystem to allocate TID to ensure uniqueness
let tid = crate::process::allocate_tid();
// Allocate stack
let stack_ptr = kmalloc::kmalloc(stack_size)?;
let stack_base = stack_ptr as usize;
let stack_top = stack_base + stack_size;
// Set up initial context
let mut context = Context::new();
context.rsp = (stack_top - 8) as u64; // Leave space for return address
context.rip = function as usize as u64;
context.rflags = 0x202; // Enable interrupts
context.cs = 0x08; // Kernel code segment
context.ds = 0x10; // Kernel data segment
context.es = 0x10;
context.fs = 0x10;
context.gs = 0x10;
context.ss = 0x10;
// Write a dummy return address to stack (for if function returns)
unsafe {
let return_addr_ptr = (stack_top - 8) as *mut u64;
*return_addr_ptr = task_exit_wrapper as usize as u64;
}
Ok(Task {
tid,
pid: Pid(0), // Kernel process
name,
state: TaskState::Ready,
context,
stack_base,
stack_size,
priority: 128, // Default priority
cpu_time: 0,
creation_time: crate::time::get_jiffies().0,
})
}
/// Set task priority
pub fn set_priority(&mut self, priority: u8) {
self.priority = priority;
}
/// Update CPU time
pub fn add_cpu_time(&mut self, time: u64) {
self.cpu_time += time;
}
/// Check if task should be scheduled
pub fn is_schedulable(&self) -> bool {
matches!(self.state, TaskState::Ready | TaskState::Running)
}
/// Terminate task
pub fn terminate(&mut self) {
self.state = TaskState::Terminated;
// Free stack memory
unsafe {
kmalloc::kfree(self.stack_base as *mut u8);
}
}
}
/// Wrapper function called when a task function returns
extern "C" fn task_exit_wrapper() -> ! {
crate::info!("Kernel task exited normally");
// Mark current task as terminated
if let Some(current_tid) = crate::enhanced_scheduler::get_current_task() {
let _ = crate::enhanced_scheduler::remove_task(current_tid);
}
// Yield to scheduler
loop {
crate::enhanced_scheduler::schedule_next();
// If we get here, no other tasks to schedule
unsafe {
core::arch::asm!("hlt");
}
}
}
/// Working task manager
pub struct TaskManager {
tasks: Spinlock<Vec<Task>>,
next_tid: AtomicU32,
}
impl TaskManager {
pub const fn new() -> Self {
Self {
tasks: Spinlock::new(Vec::new()),
next_tid: AtomicU32::new(1),
}
}
/// Spawn a new kernel task
pub fn spawn_kernel_task(
&self,
name: String,
function: TaskFunction,
stack_size: usize,
) -> Result<Tid> {
let task = Task::new_kernel_task(name.clone(), function, stack_size)?;
let tid = task.tid;
// Add to local task list
self.tasks.lock().push(task.clone());
// Add to PROCESS_TABLE so the low-level scheduler can find it
crate::process::add_kernel_thread(
tid,
task.context,
crate::memory::VirtAddr::new(task.context.rsp as usize),
)?;
// Add to enhanced scheduler
crate::enhanced_scheduler::add_task(
format!("task-{}", tid.0),
crate::enhanced_scheduler::Priority::Normal,
)?;
crate::info!(
"Spawned kernel task {} with TID {:?}",
format!("task-{}", tid.0),
tid
);
Ok(tid)
}
/// Get task by TID
pub fn get_task(&self, tid: Tid) -> Option<Task> {
self.tasks
.lock()
.iter()
.find(|task| task.tid == tid)
.cloned()
}
/// Update task state
pub fn set_task_state(&self, tid: Tid, state: TaskState) -> Result<()> {
let mut tasks = self.tasks.lock();
match tasks.iter_mut().find(|task| task.tid == tid) {
Some(task) => {
task.state = state;
Ok(())
}
None => Err(Error::NotFound),
}
}
/// Get all tasks
pub fn get_all_tasks(&self) -> Vec<Task> {
self.tasks.lock().clone()
}
/// Clean up terminated tasks
pub fn cleanup_terminated_tasks(&self) {
let mut tasks = self.tasks.lock();
tasks.retain(|task| task.state != TaskState::Terminated);
}
/// Get total number of tasks
pub fn get_task_count(&self) -> usize {
self.tasks.lock().len()
}
}
/// Global task manager
static TASK_MANAGER: TaskManager = TaskManager::new();
/// Initialize task management
pub fn init_task_management() -> Result<()> {
crate::info!("Task management initialized");
Ok(())
}
/// Spawn a kernel task
pub fn spawn_kernel_task(name: String, function: TaskFunction, stack_size: usize) -> Result<Tid> {
TASK_MANAGER.spawn_kernel_task(name, function, stack_size)
}
/// Create and spawn a kernel task (alias for compatibility)
pub fn create_kernel_task(name: &str, function: TaskFunction) -> Result<Tid> {
spawn_kernel_task(name.to_string(), function, 8192) // 8KB default stack
}
/// Get task information
pub fn get_task_info(tid: Tid) -> Option<Task> {
TASK_MANAGER.get_task(tid)
}
/// Set task state
pub fn set_task_state(tid: Tid, state: TaskState) -> Result<()> {
TASK_MANAGER.set_task_state(tid, state)
}
/// Get all tasks
pub fn get_all_tasks() -> Vec<Task> {
TASK_MANAGER.get_all_tasks()
}
/// Clean up terminated tasks
pub fn cleanup_tasks() {
TASK_MANAGER.cleanup_terminated_tasks();
}
/// Get total task count
pub fn get_task_count() -> usize {
TASK_MANAGER.get_task_count()
}
/// Example kernel tasks for testing
/// Idle task that runs when no other tasks are ready
pub fn idle_task() {
loop {
unsafe {
core::arch::asm!("hlt"); // Halt until interrupt
}
}
}
/// Heartbeat task that prints periodic messages
pub fn heartbeat_task() {
let mut counter = 0;
loop {
counter += 1;
crate::info!("Heartbeat: {}", counter);
// Sleep for a while (simplified - just loop)
for _ in 0..1_000_000 {
unsafe {
core::arch::asm!("pause");
}
}
if counter >= 10 {
crate::info!("Heartbeat task exiting after 10 beats");
break;
}
}
}
/// Memory monitor task
pub fn memory_monitor_task() {
loop {
let stats = crate::memory::advanced_allocator::get_memory_stats();
crate::info!(
"Memory: allocated={} KB, peak={} KB, active_allocs={}",
stats.current_allocated / 1024,
stats.peak_usage / 1024,
stats.active_allocations
);
// Sleep for a while
for _ in 0..5_000_000 {
unsafe {
core::arch::asm!("pause");
}
}
}
}
/// Performance monitor task
pub fn performance_monitor_task() {
loop {
let summary = crate::advanced_perf::get_performance_summary();
let mut total_counters = 0;
for (_, value) in &summary.counters {
total_counters += value;
}
if total_counters > 0 {
crate::info!(
"Performance: {} events, {} profilers active",
summary.total_events,
summary.profilers.len()
);
}
// Sleep for a while
for _ in 0..10_000_000 {
unsafe {
core::arch::asm!("pause");
}
}
}
}