Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2025-12-02 00:03:46 +01:00
padre 315b8aa0f5
commit f9be9904fc
Se han modificado 29 ficheros con 419 adiciones y 325 borrados

Ver fichero

@@ -3,6 +3,11 @@ target = "x86_64-unknown-none"
[target.x86_64-unknown-none] [target.x86_64-unknown-none]
runner = "qemu-system-x86_64 -kernel" runner = "qemu-system-x86_64 -kernel"
rustflags = [
"-C", "relocation-model=static",
"-C", "link-arg=-Tkernel/linker.ld",
"-C", "link-arg=-no-pie"
]
[unstable] [unstable]
build-std = ["core", "alloc"] build-std = ["core", "alloc"]

Ver fichero

@@ -29,7 +29,7 @@ all: kernel modules drivers
# Build the core kernel # Build the core kernel
kernel: kernel:
@echo "Building Rust kernel ($(ARCH), $(BUILD_TYPE))" @echo "Building Rust kernel ($(ARCH), $(BUILD_TYPE))"
cd kernel && $(CARGO) build $(CARGO_FLAGS) --target x86_64-unknown-none -Z build-std=core,alloc $(CARGO) build $(CARGO_FLAGS) --bin rust-kernel --target x86_64-unknown-none
# Build kernel modules # Build kernel modules
modules: $(RUST_MODULES) modules: $(RUST_MODULES)

Ver fichero

@@ -315,8 +315,8 @@ perf counters # Show performance counters
- **Memory Mapping**: Support for memory-mapped I/O and files - **Memory Mapping**: Support for memory-mapped I/O and files
### Process & Task Management ### Process & Task Management
- **Preemptive Scheduling**: Priority-based with round-robin - **Preemptive Scheduling**: Priority-based with round-robin and CFS (Completely Fair Scheduler)
- **Context Switching**: Full CPU context preservation - **Context Switching**: Full CPU context preservation including GPRs, segment registers, and control registers
- **Kernel Threads**: Lightweight kernel task execution - **Kernel Threads**: Lightweight kernel task execution
- **Process States**: Running, ready, waiting, zombie states - **Process States**: Running, ready, waiting, zombie states
@@ -360,6 +360,7 @@ perf counters # Show performance counters
### 📋 **Future Enhancements** ### 📋 **Future Enhancements**
- [ ] SMP (multi-processor) support - [ ] SMP (multi-processor) support
- [ ] ACPI (Advanced Configuration and Power Interface) support
- [ ] Advanced file systems (ext2, FAT32) - [ ] Advanced file systems (ext2, FAT32)
- [ ] Complete TCP/IP networking stack - [ ] Complete TCP/IP networking stack
- [ ] Graphics and display support - [ ] Graphics and display support

Ver fichero

@@ -8,6 +8,9 @@ set -e # Exit on any error
echo "=== Rust Kernel Build and Test Script ===" echo "=== Rust Kernel Build and Test Script ==="
echo "Starting comprehensive build and validation..." echo "Starting comprehensive build and validation..."
# Enable unstable features on stable compiler
export RUSTC_BOOTSTRAP=1
# Colors for output # Colors for output
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
@@ -84,7 +87,7 @@ fi
# Run Clippy lints (if available) # Run Clippy lints (if available)
print_status "Running Clippy lints..." print_status "Running Clippy lints..."
if command -v cargo-clippy &> /dev/null; then if command -v cargo-clippy &> /dev/null; then
if RUSTFLAGS="-Awarnings" cargo clippy -- -D warnings > /tmp/clippy.log 2>&1; then if cargo clippy -- -D warnings > /tmp/clippy.log 2>&1; then
print_success "Clippy lints passed" print_success "Clippy lints passed"
else else
print_warning "Clippy found issues (continuing with build)" print_warning "Clippy found issues (continuing with build)"
@@ -97,18 +100,18 @@ fi
# Build in debug mode # Build in debug mode
print_status "Building kernel in debug mode..." print_status "Building kernel in debug mode..."
run_with_status "RUSTFLAGS='-Awarnings' cargo check" "Debug build check" run_with_status "cargo check" "Debug build check"
print_success "Debug build completed successfully" print_success "Debug build completed successfully"
# Build in release mode # Build in release mode
print_status "Building kernel in release mode..." print_status "Building kernel in release mode..."
run_with_status "RUSTFLAGS='-Awarnings' cargo check --release" "Release build check" run_with_status "cargo check --release" "Release build check"
print_success "Release build completed successfully" print_success "Release build completed successfully"
# Build with make (if Makefile exists) # Build with make (if Makefile exists)
if [ -f "Makefile" ]; then if [ -f "Makefile" ]; then
print_status "Building with Makefile..." print_status "Building with Makefile..."
run_with_status "RUSTFLAGS='-Awarnings' make kernel" "Makefile build" run_with_status "make kernel" "Makefile build"
print_success "Makefile build completed successfully" print_success "Makefile build completed successfully"
else else
print_warning "Makefile not found, skipping make build" print_warning "Makefile not found, skipping make build"
@@ -125,6 +128,15 @@ if [ -f "target/release/deps/kernel-"*.rlib ]; then
print_status "Kernel library size: $KERNEL_SIZE" print_status "Kernel library size: $KERNEL_SIZE"
fi fi
# Create ISO
print_status "Creating bootable ISO..."
cp target/x86_64-unknown-none/release/rust-kernel iso/boot/rust-kernel
if grub-mkrescue -o rust-kernel.iso iso > /dev/null 2>&1; then
print_success "ISO created: rust-kernel.iso"
else
print_warning "Failed to create ISO (grub-mkrescue not found or failed)"
fi
# Create build report # Create build report
BUILD_REPORT="build_report.txt" BUILD_REPORT="build_report.txt"
print_status "Generating build report..." print_status "Generating build report..."
@@ -198,7 +210,7 @@ print_status "Test suites available: 15+ test categories"
echo "" echo ""
echo "To test the kernel:" echo "To test the kernel:"
echo " 1. Boot in QEMU: qemu-system-x86_64 -kernel target/release/..." echo " 1. Boot in QEMU: qemu-system-x86_64 -cdrom rust-kernel.iso"
echo " 2. Use shell commands like: 'test run', 'sysinfo', 'health'" echo " 2. Use shell commands like: 'test run', 'sysinfo', 'health'"
echo " 3. Monitor system status with: 'diag', 'perf', 'mem'" echo " 3. Monitor system status with: 'diag', 'perf', 'mem'"

Ver fichero

@@ -1,21 +1,21 @@
# Clippy configuration for kernel development # Clippy configuration for kernel development
allow = [ # allow = [
"clippy::missing_errors_doc", # "clippy::missing_errors_doc",
"clippy::missing_panics_doc", # "clippy::missing_panics_doc",
"clippy::module_name_repetitions", # "clippy::module_name_repetitions",
"clippy::inline_always", # "clippy::inline_always",
"clippy::must_use_candidate", # "clippy::must_use_candidate",
"clippy::cast_possible_truncation", # "clippy::cast_possible_truncation",
"clippy::cast_sign_loss", # "clippy::cast_sign_loss",
"clippy::cast_possible_wrap", # "clippy::cast_possible_wrap",
"clippy::similar_names", # "clippy::similar_names",
"clippy::too_many_lines", # "clippy::too_many_lines",
"clippy::unused_self" # "clippy::unused_self"
] # ]
# Kernel-specific thresholds # Kernel-specific thresholds
cognitive-complexity-threshold = 30 cognitive-complexity-threshold = 30
too-many-arguments-threshold = 8 too-many-arguments-threshold = 8
type-complexity-threshold = 250 type-complexity-threshold = 250
single-char-lifetime-names-threshold = 4 # single-char-lifetime-names-threshold = 4

Ver fichero

@@ -2,6 +2,6 @@ set timeout=0
set default=0 set default=0
menuentry "Rust Kernel" { menuentry "Rust Kernel" {
multiboot /boot/rust-kernel multiboot2 /boot/rust-kernel
boot boot
} }

Archivo binario no mostrado.

Ver fichero

@@ -4,10 +4,9 @@ rustflags = [
"-C", "link-arg=-static", "-C", "link-arg=-static",
"-C", "relocation-model=static", "-C", "relocation-model=static",
"-C", "link-arg=-no-pie", "-C", "link-arg=-no-pie",
"-C", "link-arg=-fno-pie",
"-C", "link-arg=-z", "-C", "link-arg=-z",
"-C", "link-arg=max-page-size=0x1000", "-C", "link-arg=max-page-size=0x1000",
"-C", "link-arg=-Wl,--oformat=elf64-x86-64", "-C", "link-arg=--oformat=elf64-x86-64",
] ]
[build] [build]

Ver fichero

@@ -10,10 +10,6 @@ license = "GPL-2.0"
name = "kernel" name = "kernel"
crate-type = ["rlib"] crate-type = ["rlib"]
[[bin]]
name = "rust-kernel"
path = "src/main.rs"
[dependencies] [dependencies]
spin = "0.9" spin = "0.9"
bitflags = "2.4" bitflags = "2.4"

Ver fichero

@@ -11,8 +11,7 @@ fn main() {
// Copy linker script to OUT_DIR so the linker can find it // Copy linker script to OUT_DIR so the linker can find it
let linker_script = out_dir.join("linker.ld"); let linker_script = out_dir.join("linker.ld");
fs::copy("linker.ld", &linker_script) fs::copy("linker.ld", &linker_script).expect("Failed to copy linker script");
.expect("Failed to copy linker script");
// Tell cargo to pass the linker script to the linker // Tell cargo to pass the linker script to the linker
println!("cargo:rustc-link-arg=-T{}", linker_script.display()); println!("cargo:rustc-link-arg=-T{}", linker_script.display());

Ver fichero

@@ -40,6 +40,7 @@ SECTIONS
/* Read-write data */ /* Read-write data */
.data : ALIGN(4K) { .data : ALIGN(4K) {
*(.data .data.*) *(.data .data.*)
*(.got .got.*)
} :data } :data
/* BSS section (uninitialized data) */ /* BSS section (uninitialized data) */

Ver fichero

@@ -1,7 +1,15 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
# Rust Kernel boot entry point for x86_64 # Rust Kernel boot entry point for x86_64
.section .multiboot_header .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: header_start:
# Multiboot2 header # Multiboot2 header
.long 0xe85250d6 # magic number .long 0xe85250d6 # magic number
@@ -21,6 +29,8 @@ header_end:
.section .bss .section .bss
multiboot_magic_store: multiboot_magic_store:
.skip 4 .skip 4
multiboot_info_store:
.skip 4
# Stack for the kernel # Stack for the kernel
.global stack_bottom .global stack_bottom
.global stack_top .global stack_top
@@ -30,16 +40,16 @@ stack_top:
# Bootstrap page tables # Bootstrap page tables
.align 4096 .align 4096
.global boot_page_directory_ptr_table .global boot_pml4
boot_page_directory_ptr_table: boot_pml4:
.skip 4096 .skip 4096
.global boot_page_directory_table .global boot_pdp
boot_page_directory_table: boot_pdp:
.skip 4096 .skip 4096
.global boot_page_table .global boot_pd
boot_page_table: boot_pd:
.skip 4096 .skip 4096
.section .rodata .section .rodata
@@ -49,7 +59,7 @@ gdt64:
.quad (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53) # code segment .quad (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53) # code segment
.set gdt64.data, . - gdt64 .set gdt64.data, . - gdt64
.quad (1<<44) | (1<<47) | (1<<41) # data segment .quad (1<<44) | (1<<47) | (1<<41) # data segment
.set gdt64.pointer, . - gdt64 gdt64.pointer:
.word . - gdt64 - 1 # length .word . - gdt64 - 1 # length
.quad gdt64 # address .quad gdt64 # address
@@ -61,13 +71,21 @@ _start:
movl $stack_top, %esp movl $stack_top, %esp
movl %esp, %ebp movl %esp, %ebp
# Save multiboot information before we lose it # Save multiboot information before we lose it or clobber EAX
movl %eax, multiboot_magic_store movl %eax, multiboot_magic_store
movl %ebx, multiboot_info_store movl %ebx, multiboot_info_store
# Restore magic for check (or use stored value)
movl multiboot_magic_store, %eax
# Check for multiboot # Check for multiboot
cmpl $0x36d76289, %eax cmpl $0x36d76289, %eax
jne no_multiboot je .multiboot_ok
cmpl $0x2BADB002, %eax
je .multiboot_ok
jmp no_multiboot
.multiboot_ok:
# Check for CPUID # Check for CPUID
call check_cpuid call check_cpuid
@@ -88,7 +106,7 @@ _start:
movl %eax, %cr4 movl %eax, %cr4
# Load page table # Load page table
movl $boot_page_directory_ptr_table, %eax movl $boot_pml4, %eax
movl %eax, %cr3 movl %eax, %cr3
# Enable long mode # Enable long mode
@@ -121,7 +139,7 @@ check_cpuid:
pushl %ecx pushl %ecx
popfl popfl
cmpl %ecx, %eax cmpl %ecx, %eax
sete %al setne %al
movzbl %al, %eax movzbl %al, %eax
ret ret
@@ -136,7 +154,7 @@ check_long_mode:
movl $0x80000001, %eax movl $0x80000001, %eax
cpuid cpuid
testl $1 << 29, %edx testl $1 << 29, %edx
setz %al setnz %al
movzbl %al, %eax movzbl %al, %eax
ret ret
@@ -145,30 +163,28 @@ check_long_mode:
ret ret
setup_page_tables: setup_page_tables:
# Map first 2MB with 2MB pages # Map PML4[0] -> PDP
# PDP table entry movl $boot_pdp, %eax
movl $boot_page_directory_table, %eax
orl $0b11, %eax # present + writable orl $0b11, %eax # present + writable
movl %eax, boot_page_directory_ptr_table movl %eax, boot_pml4
# PD table entry # Map PDP[0] -> PD
movl $boot_page_table, %eax movl $boot_pd, %eax
orl $0b11, %eax # present + writable orl $0b11, %eax # present + writable
movl %eax, boot_page_directory_table movl %eax, boot_pdp
# Page table entries (identity map first 2MB) # Map PD[0..511] -> 2MB Pages (Identity map 0-1GB)
movl $boot_page_table, %edi movl $boot_pd, %edi
movl $0, %ebx movl $0, %ebx # Physical address
movl $512, %ecx movl $512, %ecx # 512 entries
.map_page_table: .map_pd_loop:
movl %ebx, %eax movl %ebx, %eax
shll $12, %eax # multiply by 4096 (page size) orl $0b10000011, %eax # present + writable + huge (2MB)
orl $0b11, %eax # present + writable
movl %eax, (%edi) movl %eax, (%edi)
addl $8, %edi addl $8, %edi # Next entry
incl %ebx addl $0x200000, %ebx # Next 2MB
loop .map_page_table loop .map_pd_loop
ret ret
@@ -228,6 +244,10 @@ print_string:
ret ret
no_multiboot: no_multiboot:
# DEBUG: Print 'M' to serial port COM1
mov $0x3f8, %dx
mov $'M', %al
out %al, %dx
movl $no_multiboot_msg, %esi movl $no_multiboot_msg, %esi
call print_string_32 call print_string_32
jmp halt32 jmp halt32
@@ -272,3 +292,5 @@ no_cpuid_msg:
no_long_mode_msg: no_long_mode_msg:
.asciz "ERROR: Long mode not supported" .asciz "ERROR: Long mode not supported"

Ver fichero

@@ -1,44 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
# Kernel entry point - multiboot compliant
.section .multiboot
.align 4
# Multiboot header
multiboot_header:
.long 0x1BADB002 # Magic number
.long 0x00000003 # Flags (align modules on page boundaries + memory info)
.long -(0x1BADB002 + 0x00000003) # Checksum
.section .bss
.align 16
stack_bottom:
.skip 16384 # 16 KB stack
stack_top:
.section .text
.global _start
.type _start, @function
_start:
# Set up the stack
mov $stack_top, %esp
# Reset EFLAGS
pushl $0
popf
# Push multiboot parameters
pushl %ebx # Multiboot info structure
pushl %eax # Multiboot magic number
# Call the kernel main function
call kernel_main_multiboot
# If kernel returns (shouldn't happen), hang
cli
hang:
hlt
jmp hang
.size _start, . - _start

Ver fichero

@@ -166,31 +166,87 @@ impl Context {
/// Restore CPU context and switch to it /// Restore CPU context and switch to it
pub unsafe fn restore(&self) -> ! { pub unsafe fn restore(&self) -> ! {
// For now, implement a simplified version that doesn't cause register pressure // Restore context using the pointer to self (passed in rdi)
// TODO: Implement full context switching with proper register restoration
// Restore page table
asm!("mov cr3, {}", in(reg) self.cr3);
// Set up a minimal context switch by jumping to the target RIP
// This is a simplified version - a full implementation would restore all
// registers
asm!( asm!(
"mov rsp, {}", // Restore CR3 (Page Table)
"push {}", // CS for iretq "mov rax, [rdi + 144]",
"push {}", // RIP for iretq "mov cr3, rax",
"pushfq", // Push current flags
// 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", "pop rax",
"or rax, 0x200", // Enable interrupts
"push rax", // RFLAGS for iretq // Return from interrupt (restores RIP, CS, RFLAGS, RSP, SS)
"push {}", // CS again
"push {}", // RIP again
"iretq", "iretq",
in(reg) self.rsp, in("rdi") self,
in(reg) self.cs as u64,
in(reg) self.rip,
in(reg) self.cs as u64,
in(reg) self.rip,
options(noreturn) options(noreturn)
); );
} }

Ver fichero

@@ -74,7 +74,9 @@ pub fn get_boot_info() -> &'static BootInfo {
/// Update boot information /// Update boot information
pub unsafe fn update_boot_info<F>(f: F) pub unsafe fn update_boot_info<F>(f: F)
where F: FnOnce(&mut BootInfo) { where
F: FnOnce(&mut BootInfo),
{
f(&mut BOOT_INFO); f(&mut BOOT_INFO);
} }
@@ -114,7 +116,8 @@ pub mod multiboot {
pub struct BootMemoryInfo { pub struct BootMemoryInfo {
pub total_memory: u64, pub total_memory: u64,
pub available_memory: u64, pub available_memory: u64,
pub memory_regions: alloc::vec::Vec<MemoryMapEntry>, pub memory_regions: [MemoryMapEntry; 32],
pub region_count: usize,
} }
impl BootMemoryInfo { impl BootMemoryInfo {
@@ -122,7 +125,13 @@ pub mod multiboot {
Self { Self {
total_memory: 0, total_memory: 0,
available_memory: 0, available_memory: 0,
memory_regions: alloc::vec::Vec::new(), memory_regions: [MemoryMapEntry {
base_addr: 0,
length: 0,
type_: 0,
reserved: 0,
}; 32],
region_count: 0,
} }
} }
@@ -131,17 +140,20 @@ pub mod multiboot {
self.available_memory += entry.length; self.available_memory += entry.length;
} }
self.total_memory += entry.length; self.total_memory += entry.length;
self.memory_regions.push(entry); if self.region_count < 32 {
self.memory_regions[self.region_count] = entry;
self.region_count += 1;
}
} }
} }
/// Parse multiboot2 information and initialize memory management /// Parse multiboot2 information and initialize memory management
pub fn init_memory_from_multiboot(multiboot_addr: usize) -> Result<()> { pub fn init_memory_from_multiboot(multiboot_addr: usize) -> Result<()> {
info!("Parsing multiboot information at 0x{:x}", multiboot_addr); crate::println!("Parsing multiboot information at 0x{:x}", multiboot_addr);
let multiboot_info = unsafe { &*(multiboot_addr as *const MultibootInfo) }; let multiboot_info = unsafe { &*(multiboot_addr as *const MultibootInfo) };
info!("Multiboot info size: {} bytes", multiboot_info.total_size); crate::println!("Multiboot info size: {} bytes", multiboot_info.total_size);
// Parse memory map from multiboot info // Parse memory map from multiboot info
let mut memory_info = BootMemoryInfo::new(); let mut memory_info = BootMemoryInfo::new();
@@ -166,12 +178,13 @@ pub mod multiboot {
} }
// Initialize page allocator with available memory // Initialize page allocator with available memory
for region in &memory_info.memory_regions { for i in 0..memory_info.region_count {
let region = &memory_info.memory_regions[i];
if region.type_ == memory_type::AVAILABLE { if region.type_ == memory_type::AVAILABLE {
let start_pfn = region.base_addr / 4096; let start_pfn = region.base_addr / 4096;
let end_pfn = (region.base_addr + region.length) / 4096; let end_pfn = (region.base_addr + region.length) / 4096;
info!( crate::println!(
"Adding memory region: 0x{:x}-0x{:x}", "Adding memory region: 0x{:x}-0x{:x}",
region.base_addr, region.base_addr,
region.base_addr + region.length region.base_addr + region.length
@@ -185,9 +198,9 @@ pub mod multiboot {
} }
} }
info!("Memory initialization from multiboot completed"); crate::println!("Memory initialization from multiboot completed");
info!("Total memory: {} bytes", memory_info.total_memory); crate::println!("Total memory: {} bytes", memory_info.total_memory);
info!("Available memory: {} bytes", memory_info.available_memory); crate::println!("Available memory: {} bytes", memory_info.available_memory);
Ok(()) Ok(())
} }

Ver fichero

@@ -1,41 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
# Multiboot header and boot code
.code32
.section .multiboot_header, "a"
.align 4
# Multiboot header
multiboot_header_start:
.long 0x1BADB002 # magic number (multiboot 1)
.long 0x00000000 # flags
.long -(0x1BADB002 + 0x00000000) # checksum (must sum to zero)
multiboot_header_end:
.section .text
.global _start
.type _start, @function
_start:
# Disable interrupts
cli
# Set up a basic stack (16KB)
mov $stack_top, %esp
mov $stack_top, %ebp
# Call Rust main function
call rust_main
# If rust_main returns, halt
halt_loop:
hlt
jmp halt_loop
# Reserve stack space
.section .bss
.align 16
stack_bottom:
.skip 16384 # 16KB stack
stack_top:

Ver fichero

@@ -462,7 +462,9 @@ static ENHANCED_SCHEDULER: Spinlock<Option<EnhancedScheduler>> = Spinlock::new(N
/// Helper to get scheduler reference safely /// Helper to get scheduler reference safely
fn with_scheduler<T, F>(f: F) -> Option<T> fn with_scheduler<T, F>(f: F) -> Option<T>
where F: FnOnce(&mut EnhancedScheduler) -> T { where
F: FnOnce(&mut EnhancedScheduler) -> T,
{
let mut scheduler_option = ENHANCED_SCHEDULER.lock(); let mut scheduler_option = ENHANCED_SCHEDULER.lock();
if let Some(ref mut scheduler) = *scheduler_option { if let Some(ref mut scheduler) = *scheduler_option {
Some(f(scheduler)) Some(f(scheduler))
@@ -473,7 +475,9 @@ where F: FnOnce(&mut EnhancedScheduler) -> T {
/// Helper to get read-only scheduler reference safely /// Helper to get read-only scheduler reference safely
fn with_scheduler_read<T, F>(f: F) -> Option<T> fn with_scheduler_read<T, F>(f: F) -> Option<T>
where F: FnOnce(&EnhancedScheduler) -> T { where
F: FnOnce(&EnhancedScheduler) -> T,
{
let scheduler_option = ENHANCED_SCHEDULER.lock(); let scheduler_option = ENHANCED_SCHEDULER.lock();
if let Some(ref scheduler) = *scheduler_option { if let Some(ref scheduler) = *scheduler_option {
Some(f(scheduler)) Some(f(scheduler))

Ver fichero

@@ -18,6 +18,10 @@
extern crate alloc; 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 arch; pub mod arch;
pub mod benchmark; // Performance benchmarking pub mod benchmark; // Performance benchmarking
pub mod boot; pub mod boot;
@@ -94,7 +98,7 @@ pub extern "C" fn kernel_main() -> ! {
#[no_mangle] #[no_mangle]
pub extern "C" fn kernel_main_multiboot(multiboot_magic: u32, multiboot_addr: u32) -> ! { pub extern "C" fn kernel_main_multiboot(multiboot_magic: u32, multiboot_addr: u32) -> ! {
// Verify multiboot magic number // Verify multiboot magic number
if multiboot_magic != 0x36d76289 { if multiboot_magic != 0x36d76289 && multiboot_magic != 0x2BADB002 {
panic!("Invalid multiboot magic: 0x{:x}", multiboot_magic); panic!("Invalid multiboot magic: 0x{:x}", multiboot_magic);
} }
@@ -113,8 +117,8 @@ fn early_kernel_init() {
loop {} loop {}
} }
info!("Rust Kernel v{} starting...", VERSION); crate::println!("Rust Kernel v{} starting...", VERSION);
info!("Early kernel initialization"); crate::println!("Early kernel initialization");
} }
/// Initialize memory management using multiboot information /// Initialize memory management using multiboot information

Ver fichero

@@ -5,6 +5,16 @@
#![no_std] #![no_std]
#![no_main] #![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));
use core::panic::PanicInfo;
/// Multiboot1 header - placed at the very beginning /// Multiboot1 header - placed at the very beginning
#[repr(C)] #[repr(C)]
#[repr(packed)] #[repr(packed)]
@@ -15,60 +25,21 @@ struct MultibootHeader {
} }
/// Multiboot header must be in the first 8KB and be 4-byte aligned /// Multiboot header must be in the first 8KB and be 4-byte aligned
#[link_section = ".multiboot_header"] // #[link_section = ".multiboot_header"]
#[no_mangle] // #[no_mangle]
#[used] // #[used]
static MULTIBOOT_HEADER: MultibootHeader = MultibootHeader { // static MULTIBOOT_HEADER: MultibootHeader = MultibootHeader {
magic: 0x1BADB002, // magic: 0x1BADB002,
flags: 0x00000000, // flags: 0x00000000,
checksum: 0u32.wrapping_sub(0x1BADB002u32.wrapping_add(0x00000000)), // checksum: 0u32.wrapping_sub(0x1BADB002u32.wrapping_add(0x00000000)),
}; // };
/// Entry point called by boot.s assembly code /// Entry point called by boot.s assembly code
/// This is just a wrapper to ensure the kernel crate is linked
#[no_mangle] #[no_mangle]
pub extern "C" fn rust_main() -> ! { pub extern "C" fn rust_main() -> ! {
kernel_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
/// Main kernel function
fn kernel_main() -> ! {
// Start with the simplest possible approach
unsafe {
let vga_buffer = 0xb8000 as *mut u16;
// Clear screen
for i in 0..80*25 {
*vga_buffer.offset(i) = 0x0f20; // White space on black background
}
// Display kernel info
let messages = [
"Rust Kernel v1.0 - Successfully Booted!",
"",
"Available commands:",
" help - Show this help",
" version - Show kernel version",
" clear - Clear screen",
" reboot - Restart system",
"",
"rustos> ",
];
let mut row = 0;
for message in &messages {
let mut col = 0;
for byte in message.bytes() {
if col < 80 {
let vga_entry = (0x0f00 | byte as u16); // White text on black background
*vga_buffer.offset((row * 80 + col) as isize) = vga_entry;
col += 1;
}
}
row += 1;
}
}
// Simple command loop (just display, no real interaction yet)
loop { loop {
unsafe { unsafe {
core::arch::asm!("hlt"); core::arch::asm!("hlt");
@@ -76,12 +47,9 @@ fn kernel_main() -> ! {
} }
} }
/// Panic handler - required for no_std // Panic handler is defined in the kernel library
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! { #[no_mangle]
loop { pub extern "C" fn _start() -> ! {
unsafe { loop {}
core::arch::asm!("hlt");
}
}
} }

Ver fichero

@@ -2,7 +2,6 @@
//! Page frame allocator //! Page frame allocator
use alloc::collections::BTreeSet;
use core::sync::atomic::{AtomicU32, Ordering}; use core::sync::atomic::{AtomicU32, Ordering};
use crate::error::{Error, Result}; use crate::error::{Error, Result};
@@ -98,34 +97,57 @@ pub static PAGE_ALLOCATOR: Spinlock<PageAllocator> = Spinlock::new(PageAllocator
/// Page allocator implementation /// Page allocator implementation
pub struct PageAllocator { pub struct PageAllocator {
free_pages: BTreeSet<Pfn>, free_list_head: Option<PhysAddr>,
total_pages: usize, total_pages: usize,
allocated_pages: usize, allocated_pages: usize,
free_count: usize,
} }
impl PageAllocator { impl PageAllocator {
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
free_pages: BTreeSet::new(), free_list_head: None,
total_pages: 0, total_pages: 0,
allocated_pages: 0, allocated_pages: 0,
free_count: 0,
} }
} }
/// Add a range of pages to the free list /// Add a range of pages to the free list
pub fn add_free_range(&mut self, start: Pfn, count: usize) { pub fn add_free_range(&mut self, start: Pfn, count: usize) {
for i in 0..count { for i in 0..count {
self.free_pages.insert(Pfn(start.0 + i)); 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 += count; self.total_pages += count;
self.free_count += count;
} }
/// Allocate a single page /// Allocate a single page
fn alloc_page(&mut self) -> Result<Pfn> { fn alloc_page(&mut self) -> Result<Pfn> {
if let Some(pfn) = self.free_pages.iter().next().copied() { if let Some(head_addr) = self.free_list_head {
self.free_pages.remove(&pfn); // 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.allocated_pages += 1;
Ok(pfn) self.free_count -= 1;
Ok(Pfn(head_addr.0 / 4096))
} else { } else {
Err(Error::OutOfMemory) Err(Error::OutOfMemory)
} }
@@ -133,18 +155,19 @@ impl PageAllocator {
/// Free a single page /// Free a single page
fn free_page(&mut self, pfn: Pfn) { fn free_page(&mut self, pfn: Pfn) {
if self.free_pages.insert(pfn) { let phys_addr = PhysAddr(pfn.0 * 4096);
self.allocated_pages -= 1; 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 /// Get statistics
fn stats(&self) -> (usize, usize, usize) { fn stats(&self) -> (usize, usize, usize) {
( (self.total_pages, self.allocated_pages, self.free_count)
self.total_pages,
self.allocated_pages,
self.free_pages.len(),
)
} }
} }

Ver fichero

@@ -1,16 +0,0 @@
.section .multiboot_header
.align 4
.long 0x1BADB002 /* magic */
.long 0x00000000 /* flags */
.long -(0x1BADB002 + 0x00000000) /* checksum */
.section .text
.global _start
_start:
/* Call Rust main function */
call rust_main
/* If rust_main returns, halt */
1: hlt
jmp 1b

Ver fichero

@@ -251,6 +251,29 @@ impl ProcessTable {
} }
None 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 /// Allocate a new PID
@@ -279,6 +302,20 @@ pub fn create_process(name: String, uid: Uid, gid: Gid) -> Result<Pid> {
Ok(pid) 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 /// Get current process PID
pub fn current_process_pid() -> Option<Pid> { pub fn current_process_pid() -> Option<Pid> {
let table = PROCESS_TABLE.lock(); let table = PROCESS_TABLE.lock();

Ver fichero

@@ -458,32 +458,39 @@ impl Scheduler {
if let Some(current_tid) = self.current { if let Some(current_tid) = self.current {
if current_tid != tid { if current_tid != tid {
// Look up current and next threads // Look up current and next threads
let process_table = PROCESS_TABLE.lock(); // We need to use a scope to ensure the lock is dropped before switching
if let (Some(current_thread), Some(next_thread)) = ( let (current_ctx_ptr, next_ctx_ptr) = {
process_table.find_thread(current_tid), let mut process_table = PROCESS_TABLE.lock();
process_table.find_thread(tid),
) { 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 // Update scheduler state
self.current = Some(tid); self.current = Some(tid);
self.nr_switches += 1; self.nr_switches += 1;
// Drop the lock before context switch to avoid deadlock // Perform the context switch
drop(process_table); // SAFETY: We have valid pointers to the contexts and we've dropped the lock
unsafe {
// TODO: Implement actual context switch switch_context(&mut *current_ctx_ptr, &*next_ctx_ptr);
// This would involve:
// 1. Saving current thread's context
// 2. Loading next thread's context
// 3. Switching page tables if different processes
// 4. Updating stack pointer and instruction pointer
crate::info!(
"Context switch from TID {} to TID {}",
current_tid.0,
tid.0
);
return;
} }
return;
} }
} }
@@ -654,3 +661,10 @@ pub fn scheduler_tick() {
} }
} }
} }
/// 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);
}

Ver fichero

@@ -403,8 +403,37 @@ impl TimerWheel {
} }
pub fn add_timer(&mut self, timer: HrTimer) { pub fn add_timer(&mut self, timer: HrTimer) {
// TODO: Add timer to appropriate level based on expiry time let now_ns = get_time_ns();
let level = 0; // Simplified 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); self.levels[level].push(timer);
} }

Ver fichero

@@ -93,9 +93,10 @@ impl TimerState {
let mut stats = self.stats.lock(); let mut stats = self.stats.lock();
stats.context_switches += 1; stats.context_switches += 1;
// TODO: Actual context switching would happen here // Perform actual context switch
// This would involve saving current CPU state and // This will save current CPU state and restore the state of the next task
// restoring the state of the next task crate::scheduler::context_switch_to(next_tid);
crate::info!( crate::info!(
"Context switch: {:?} -> {:?}", "Context switch: {:?} -> {:?}",
current_tid, current_tid,

Ver fichero

@@ -50,8 +50,8 @@ impl Task {
function: TaskFunction, function: TaskFunction,
stack_size: usize, stack_size: usize,
) -> Result<Self> { ) -> Result<Self> {
static NEXT_TID: AtomicU32 = AtomicU32::new(1); // Use process subsystem to allocate TID to ensure uniqueness
let tid = Tid(NEXT_TID.fetch_add(1, Ordering::Relaxed)); let tid = crate::process::allocate_tid();
// Allocate stack // Allocate stack
let stack_ptr = kmalloc::kmalloc(stack_size)?; let stack_ptr = kmalloc::kmalloc(stack_size)?;
@@ -156,10 +156,18 @@ impl TaskManager {
function: TaskFunction, function: TaskFunction,
stack_size: usize, stack_size: usize,
) -> Result<Tid> { ) -> Result<Tid> {
let task = Task::new_kernel_task(name, function, stack_size)?; let task = Task::new_kernel_task(name.clone(), function, stack_size)?;
let tid = task.tid; let tid = task.tid;
self.tasks.lock().push(task); // 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 // Add to enhanced scheduler
crate::enhanced_scheduler::add_task( crate::enhanced_scheduler::add_task(

Archivo binario no mostrado.

Ver fichero

@@ -9,8 +9,11 @@
extern crate kernel; extern crate kernel;
/// Main kernel entry point use core::arch::global_asm;
#[no_mangle]
pub extern "C" fn _start() -> ! { // Include boot assembly
kernel::kernel_main() #[cfg(target_arch = "x86_64")]
} global_asm!(
include_str!("../kernel/src/arch/x86_64/boot.s"),
options(att_syntax)
);