build ok 2

Signed-off-by: ale <ale@manalejandro.com>
This commit is contained in:
ale 2025-06-15 23:53:38 +02:00
parent bbfefe2546
commit eb8069b494
Signed by: ale
GPG Key ID: 244A9C4DAB1C0C81
22 changed files with 1325 additions and 90 deletions

306
drivers/src/keyboard.rs Normal file
View File

@ -0,0 +1,306 @@
// SPDX-License-Identifier: GPL-2.0
//! PS/2 Keyboard driver
use kernel::error::{Error, Result};
use kernel::interrupt::{register_interrupt_handler, IrqHandler};
use kernel::device::{Device, DeviceType, CharDevice, FileOperations};
use kernel::sync::{Spinlock, Arc};
use kernel::arch::x86_64::port::{inb, outb};
use alloc::{string::String, vec::Vec, collections::VecDeque};
/// PS/2 keyboard controller ports
const KEYBOARD_DATA_PORT: u16 = 0x60;
const KEYBOARD_STATUS_PORT: u16 = 0x64;
const KEYBOARD_COMMAND_PORT: u16 = 0x64;
/// Keyboard scan codes to ASCII mapping (US layout, simplified)
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, // backspace
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', // enter
0, // ctrl
b'a', b's', b'd', b'f', b'g', b'h', b'j', b'k', b'l', b';', b'\'', b'`',
0, // left shift
b'\\', b'z', b'x', b'c', b'v', b'b', b'n', b'm', b',', b'.', b'/',
0, // right shift
b'*', 0, // alt
b' ', // space
0, // caps lock
// Function keys F1-F10
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // num lock
0, // scroll lock
// Numeric keypad
b'7', b'8', b'9', b'-', b'4', b'5', b'6', b'+', b'1', b'2', b'3', b'0', b'.',
0, 0, 0, // F11, F12
// Fill the rest with zeros
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
/// Keyboard state
#[derive(Debug)]
struct KeyboardState {
/// Input buffer for key presses
buffer: VecDeque<u8>,
/// Modifier key states
shift_pressed: bool,
ctrl_pressed: bool,
alt_pressed: bool,
caps_lock: bool,
}
impl KeyboardState {
fn new() -> Self {
Self {
buffer: VecDeque::new(),
shift_pressed: false,
ctrl_pressed: false,
alt_pressed: false,
caps_lock: false,
}
}
fn push_key(&mut self, key: u8) {
if self.buffer.len() < 256 { // Prevent buffer overflow
self.buffer.push_back(key);
}
}
fn pop_key(&mut self) -> Option<u8> {
self.buffer.pop_front()
}
fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
}
/// Global keyboard state
static KEYBOARD_STATE: Spinlock<KeyboardState> = Spinlock::new(KeyboardState::new());
/// Keyboard interrupt handler
#[derive(Debug)]
pub struct KeyboardIrqHandler;
impl IrqHandler for KeyboardIrqHandler {
fn handle_irq(&self, _irq: u32) -> Result<()> {
// Read scan code from keyboard data port
let scancode = unsafe { inb(KEYBOARD_DATA_PORT) };
// Process the scan code
process_scancode(scancode);
Ok(())
}
}
/// Process a keyboard scan code
fn process_scancode(scancode: u8) {
let mut keyboard = KEYBOARD_STATE.lock();
// Check if this is a key release (high bit set)
if scancode & 0x80 != 0 {
// Key release
let key_code = scancode & 0x7F;
match key_code {
0x2A | 0x36 => keyboard.shift_pressed = false, // Shift keys
0x1D => keyboard.ctrl_pressed = false, // Ctrl key
0x38 => keyboard.alt_pressed = false, // Alt key
_ => {} // Other key releases
}
return;
}
// Key press
match scancode {
0x2A | 0x36 => { // Shift keys
keyboard.shift_pressed = true;
}
0x1D => { // Ctrl key
keyboard.ctrl_pressed = true;
}
0x38 => { // Alt key
keyboard.alt_pressed = true;
}
0x3A => { // Caps Lock
keyboard.caps_lock = !keyboard.caps_lock;
}
_ => {
// Convert scan code to ASCII
if let Some(ascii) = scancode_to_ascii(scancode, &keyboard) {
keyboard.push_key(ascii);
// Echo to console for now
if ascii.is_ascii_graphic() || ascii == b' ' || ascii == b'\n' {
kernel::console::print_char(ascii as char);
}
}
}
}
}
/// Convert scan code to ASCII character
fn scancode_to_ascii(scancode: u8, keyboard: &KeyboardState) -> Option<u8> {
if scancode as usize >= SCANCODE_TO_ASCII.len() {
return None;
}
let mut ascii = SCANCODE_TO_ASCII[scancode as usize];
if ascii == 0 {
return None;
}
// Apply modifiers
if keyboard.shift_pressed || keyboard.caps_lock {
if ascii >= b'a' && ascii <= b'z' {
ascii = ascii - b'a' + b'A';
} else {
// Handle shifted symbols
ascii = match ascii {
b'1' => b'!',
b'2' => b'@',
b'3' => b'#',
b'4' => b'$',
b'5' => b'%',
b'6' => b'^',
b'7' => b'&',
b'8' => b'*',
b'9' => b'(',
b'0' => b')',
b'-' => b'_',
b'=' => b'+',
b'[' => b'{',
b']' => b'}',
b'\\' => b'|',
b';' => b':',
b'\'' => b'"',
b',' => b'<',
b'.' => b'>',
b'/' => b'?',
b'`' => b'~',
_ => ascii,
};
}
}
// Handle Ctrl combinations
if keyboard.ctrl_pressed && ascii >= b'a' && ascii <= b'z' {
ascii = ascii - b'a' + 1; // Ctrl+A = 1, Ctrl+B = 2, etc.
} else if keyboard.ctrl_pressed && ascii >= b'A' && ascii <= b'Z' {
ascii = ascii - b'A' + 1;
}
Some(ascii)
}
/// Keyboard character device file operations
#[derive(Debug)]
pub struct KeyboardFileOps;
impl FileOperations for KeyboardFileOps {
fn open(&self, _inode: &kernel::device::Inode, _file: &mut kernel::device::File) -> Result<()> {
Ok(())
}
fn release(&self, _inode: &kernel::device::Inode, _file: &mut kernel::device::File) -> Result<()> {
Ok(())
}
fn read(&self, _file: &mut kernel::device::File, buf: &mut [u8], _offset: u64) -> Result<usize> {
let mut keyboard = KEYBOARD_STATE.lock();
let mut bytes_read = 0;
// Read available characters from buffer
while bytes_read < buf.len() && !keyboard.is_empty() {
if let Some(key) = keyboard.pop_key() {
buf[bytes_read] = key;
bytes_read += 1;
// Stop at newline for line-buffered reading
if key == b'\n' {
break;
}
}
}
Ok(bytes_read)
}
fn write(&self, _file: &mut kernel::device::File, _buf: &[u8], _offset: u64) -> Result<usize> {
// Can't write to keyboard
Err(Error::EPERM)
}
fn ioctl(&self, _file: &mut kernel::device::File, _cmd: u32, _arg: usize) -> Result<usize> {
// TODO: Implement keyboard-specific ioctl commands
Err(Error::ENOTTY)
}
fn mmap(&self, _file: &mut kernel::device::File, _vma: &mut kernel::memory::VmaArea) -> Result<()> {
// Can't mmap keyboard
Err(Error::ENODEV)
}
}
/// Initialize the keyboard driver
pub fn init() -> Result<()> {
// Create keyboard device
let keyboard_device = Device::new(
"keyboard".to_string(),
DeviceType::Input,
10, // Input major number
0, // Minor number 0
);
// Register character device
let char_dev = CharDevice::new(10, 0, 1, "keyboard".to_string());
// Register interrupt handler for keyboard (IRQ 1)
let handler = Arc::new(KeyboardIrqHandler);
register_interrupt_handler(33, handler as Arc<dyn IrqHandler>)?; // IRQ 1 = INT 33
// TODO: Register device in device filesystem
Ok(())
}
/// Read a line from keyboard (blocking)
pub fn read_line() -> String {
let mut line = String::new();
loop {
let mut keyboard = KEYBOARD_STATE.lock();
while let Some(key) = keyboard.pop_key() {
if key == b'\n' {
return line;
} else if key == 8 { // Backspace
if !line.is_empty() {
line.pop();
// Move cursor back and clear character
kernel::console::print_str("\x08 \x08");
}
} else if key.is_ascii_graphic() || key == b' ' {
line.push(key as char);
}
}
drop(keyboard);
// Yield CPU while waiting for input
kernel::scheduler::yield_now();
}
}
/// Check if there are pending key presses
pub fn has_pending_input() -> bool {
let keyboard = KEYBOARD_STATE.lock();
!keyboard.is_empty()
}
/// Get next character without blocking
pub fn try_read_char() -> Option<char> {
let mut keyboard = KEYBOARD_STATE.lock();
keyboard.pop_key().map(|k| k as char)
}

View File

@ -12,6 +12,8 @@ pub mod dummy;
pub mod mem; pub mod mem;
pub mod platform_example; pub mod platform_example;
pub mod ramdisk; pub mod ramdisk;
pub mod keyboard; // New keyboard driver
pub mod serial; // New serial driver
pub use dummy::*; pub use dummy::*;
pub use mem::*; pub use mem::*;

336
drivers/src/serial.rs Normal file
View File

@ -0,0 +1,336 @@
// SPDX-License-Identifier: GPL-2.0
//! Serial console driver (16550 UART)
use kernel::error::{Error, Result};
use kernel::interrupt::{register_interrupt_handler, IrqHandler};
use kernel::device::{Device, DeviceType, CharDevice, FileOperations};
use kernel::sync::{Spinlock, Arc};
use kernel::arch::x86_64::port::{inb, outb};
use alloc::{string::String, vec::Vec, collections::VecDeque};
/// Standard COM port addresses
const COM1_BASE: u16 = 0x3F8;
const COM2_BASE: u16 = 0x2F8;
const COM3_BASE: u16 = 0x3E8;
const COM4_BASE: u16 = 0x2E8;
/// UART register offsets
const UART_DATA: u16 = 0; // Data register (R/W)
const UART_IER: u16 = 1; // Interrupt Enable Register
const UART_IIR: u16 = 2; // Interrupt Identification Register (R)
const UART_FCR: u16 = 2; // FIFO Control Register (W)
const UART_LCR: u16 = 3; // Line Control Register
const UART_MCR: u16 = 4; // Modem Control Register
const UART_LSR: u16 = 5; // Line Status Register
const UART_MSR: u16 = 6; // Modem Status Register
const UART_SCR: u16 = 7; // Scratch Register
/// Line Status Register bits
const LSR_DATA_READY: u8 = 0x01; // Data available
const LSR_OVERRUN_ERROR: u8 = 0x02; // Overrun error
const LSR_PARITY_ERROR: u8 = 0x04; // Parity error
const LSR_FRAMING_ERROR: u8 = 0x08; // Framing error
const LSR_BREAK_INTERRUPT: u8 = 0x10; // Break interrupt
const LSR_THR_EMPTY: u8 = 0x20; // Transmitter holding register empty
const LSR_THR_EMPTY_IDLE: u8 = 0x40; // Transmitter empty and idle
const LSR_FIFO_ERROR: u8 = 0x80; // FIFO error
/// Serial port structure
#[derive(Debug)]
pub struct SerialPort {
/// Base I/O port address
base: u16,
/// Port name
name: String,
/// Receive buffer
rx_buffer: VecDeque<u8>,
/// Transmit buffer
tx_buffer: VecDeque<u8>,
/// Port configuration
baudrate: u32,
data_bits: u8,
stop_bits: u8,
parity: Parity,
}
/// Parity settings
#[derive(Debug, Clone, Copy)]
pub enum Parity {
None,
Odd,
Even,
Mark,
Space,
}
impl SerialPort {
/// Create a new serial port
pub fn new(base: u16, name: String) -> Self {
Self {
base,
name,
rx_buffer: VecDeque::new(),
tx_buffer: VecDeque::new(),
baudrate: 115200,
data_bits: 8,
stop_bits: 1,
parity: Parity::None,
}
}
/// Initialize the serial port
pub fn init(&mut self) -> Result<()> {
// Disable interrupts
unsafe { outb(self.base + UART_IER, 0x00); }
// Set baud rate to 115200 (divisor = 1)
unsafe {
outb(self.base + UART_LCR, 0x80); // Enable DLAB
outb(self.base + UART_DATA, 0x01); // Divisor low byte
outb(self.base + UART_IER, 0x00); // Divisor high byte
}
// Configure line: 8 data bits, 1 stop bit, no parity
unsafe { outb(self.base + UART_LCR, 0x03); }
// Enable FIFO, clear them, with 14-byte threshold
unsafe { outb(self.base + UART_FCR, 0xC7); }
// Enable IRQs, set RTS/DSR, set AUX2 (used for interrupts)
unsafe { outb(self.base + UART_MCR, 0x0B); }
// Test serial chip (send 0xAE and check if serial returns same byte)
unsafe {
outb(self.base + UART_MCR, 0x1E); // Enable loopback mode
outb(self.base + UART_DATA, 0xAE); // Send test byte
if inb(self.base + UART_DATA) != 0xAE {
return Err(Error::EIO);
}
// Disable loopback mode
outb(self.base + UART_MCR, 0x0F);
}
// Enable interrupts
unsafe { outb(self.base + UART_IER, 0x01); } // Enable receive interrupt
Ok(())
}
/// Check if data is available for reading
pub fn is_receive_ready(&self) -> bool {
unsafe { (inb(self.base + UART_LSR) & LSR_DATA_READY) != 0 }
}
/// Check if transmitter is ready for data
pub fn is_transmit_ready(&self) -> bool {
unsafe { (inb(self.base + UART_LSR) & LSR_THR_EMPTY) != 0 }
}
/// Read a byte from the serial port (non-blocking)
pub fn read_byte(&mut self) -> Option<u8> {
if !self.rx_buffer.is_empty() {
return self.rx_buffer.pop_front();
}
if self.is_receive_ready() {
let byte = unsafe { inb(self.base + UART_DATA) };
Some(byte)
} else {
None
}
}
/// Write a byte to the serial port
pub fn write_byte(&mut self, byte: u8) -> Result<()> {
// Wait until transmitter is ready
while !self.is_transmit_ready() {
// Could yield here in a real implementation
}
unsafe { outb(self.base + UART_DATA, byte); }
Ok(())
}
/// Write a string to the serial port
pub fn write_str(&mut self, s: &str) -> Result<()> {
for byte in s.bytes() {
self.write_byte(byte)?;
}
Ok(())
}
/// Handle receive interrupt
pub fn handle_receive_interrupt(&mut self) {
while self.is_receive_ready() {
let byte = unsafe { inb(self.base + UART_DATA) };
if self.rx_buffer.len() < 1024 { // Prevent buffer overflow
self.rx_buffer.push_back(byte);
}
}
}
}
/// Global serial ports
static COM1: Spinlock<Option<SerialPort>> = Spinlock::new(None);
/// Serial interrupt handler
#[derive(Debug)]
pub struct SerialIrqHandler {
port_base: u16,
}
impl SerialIrqHandler {
pub fn new(port_base: u16) -> Self {
Self { port_base }
}
}
impl IrqHandler for SerialIrqHandler {
fn handle_irq(&self, _irq: u32) -> Result<()> {
// Handle COM1 interrupt
if self.port_base == COM1_BASE {
if let Some(ref mut port) = *COM1.lock() {
port.handle_receive_interrupt();
}
}
Ok(())
}
}
/// Serial console file operations
#[derive(Debug)]
pub struct SerialConsoleOps;
impl FileOperations for SerialConsoleOps {
fn open(&self, _inode: &kernel::device::Inode, _file: &mut kernel::device::File) -> Result<()> {
Ok(())
}
fn release(&self, _inode: &kernel::device::Inode, _file: &mut kernel::device::File) -> Result<()> {
Ok(())
}
fn read(&self, _file: &mut kernel::device::File, buf: &mut [u8], _offset: u64) -> Result<usize> {
let mut port = COM1.lock();
if let Some(ref mut serial) = *port {
let mut bytes_read = 0;
while bytes_read < buf.len() {
if let Some(byte) = serial.read_byte() {
buf[bytes_read] = byte;
bytes_read += 1;
// Stop at newline
if byte == b'\n' {
break;
}
} else {
break;
}
}
Ok(bytes_read)
} else {
Err(Error::ENODEV)
}
}
fn write(&self, _file: &mut kernel::device::File, buf: &[u8], _offset: u64) -> Result<usize> {
let mut port = COM1.lock();
if let Some(ref mut serial) = *port {
for &byte in buf {
serial.write_byte(byte)?;
}
Ok(buf.len())
} else {
Err(Error::ENODEV)
}
}
fn ioctl(&self, _file: &mut kernel::device::File, _cmd: u32, _arg: usize) -> Result<usize> {
// TODO: Implement serial-specific ioctl commands (baudrate, etc.)
Err(Error::ENOTTY)
}
fn mmap(&self, _file: &mut kernel::device::File, _vma: &mut kernel::memory::VmaArea) -> Result<()> {
Err(Error::ENODEV)
}
}
/// Initialize serial console
pub fn init() -> Result<()> {
// Initialize COM1
let mut com1 = SerialPort::new(COM1_BASE, "ttyS0".to_string());
com1.init()?;
*COM1.lock() = Some(com1);
// Register interrupt handler for COM1 (IRQ 4)
let handler = Arc::new(SerialIrqHandler::new(COM1_BASE));
register_interrupt_handler(36, handler as Arc<dyn IrqHandler>)?; // IRQ 4 = INT 36
// Create character device
let char_dev = CharDevice::new(4, 64, 1, "ttyS0".to_string());
Ok(())
}
/// Write to serial console (for kernel debugging)
pub fn serial_print(s: &str) {
let mut port = COM1.lock();
if let Some(ref mut serial) = *port {
let _ = serial.write_str(s);
}
}
/// Serial console macros
#[macro_export]
macro_rules! serial_print {
($($arg:tt)*) => {
$crate::drivers::serial::serial_print(&alloc::format!($($arg)*));
};
}
#[macro_export]
macro_rules! serial_println {
() => ($crate::serial_print!("\n"));
($($arg:tt)*) => ($crate::serial_print!("{}\n", alloc::format!($($arg)*)));
}
/// Read a line from serial console
pub fn read_line() -> Result<String> {
let mut line = String::new();
loop {
let mut port = COM1.lock();
if let Some(ref mut serial) = *port {
if let Some(byte) = serial.read_byte() {
if byte == b'\r' || byte == b'\n' {
// Echo newline
let _ = serial.write_byte(b'\n');
break;
} else if byte == 8 || byte == 127 { // Backspace or DEL
if !line.is_empty() {
line.pop();
// Echo backspace sequence
let _ = serial.write_str("\x08 \x08");
}
} else if byte.is_ascii_graphic() || byte == b' ' {
line.push(byte as char);
// Echo character
let _ = serial.write_byte(byte);
}
}
}
drop(port);
// Yield CPU while waiting
kernel::scheduler::yield_now();
}
Ok(line)
}

View File

@ -254,10 +254,12 @@ impl DeviceSubsystem {
self.devices.remove(name).ok_or(Error::NotFound) self.devices.remove(name).ok_or(Error::NotFound)
} }
#[allow(dead_code)]
fn find_device(&self, name: &str) -> Option<&Device> { fn find_device(&self, name: &str) -> Option<&Device> {
self.devices.get(name) self.devices.get(name)
} }
#[allow(dead_code)]
fn find_device_mut(&mut self, name: &str) -> Option<&mut Device> { fn find_device_mut(&mut self, name: &str) -> Option<&mut Device> {
self.devices.get_mut(name) self.devices.get_mut(name)
} }

View File

@ -264,6 +264,7 @@ impl DriverSubsystem {
} }
} }
#[allow(dead_code)]
fn find_driver(&self, name: &str) -> Option<&dyn Driver> { fn find_driver(&self, name: &str) -> Option<&dyn Driver> {
self.drivers.get(name).map(|d| d.as_ref()) self.drivers.get(name).map(|d| d.as_ref())
} }

View File

@ -29,6 +29,12 @@ pub enum Error {
Device, Device,
/// Generic error /// Generic error
Generic, Generic,
/// Invalid operation
InvalidOperation,
/// Timeout
Timeout,
/// Not initialized
NotInitialized, // New error variant
// Linux-compatible errno values // Linux-compatible errno values
/// Operation not permitted (EPERM) /// Operation not permitted (EPERM)
@ -59,6 +65,10 @@ pub enum Error {
EEXIST, EEXIST,
/// Directory not empty (ENOTEMPTY) /// Directory not empty (ENOTEMPTY)
ENOTEMPTY, ENOTEMPTY,
/// No child process (ECHILD)
ECHILD,
/// No such process (ESRCH)
ESRCH,
} }
impl Error { impl Error {
@ -76,6 +86,9 @@ impl Error {
Error::WouldBlock => -11, // EAGAIN Error::WouldBlock => -11, // EAGAIN
Error::Device => -19, // ENODEV Error::Device => -19, // ENODEV
Error::Generic => -1, // EPERM Error::Generic => -1, // EPERM
Error::InvalidOperation => -1, // EPERM
Error::Timeout => -110, // ETIMEDOUT
Error::NotInitialized => -6, // ENXIO
// Linux errno mappings // Linux errno mappings
Error::EPERM => -1, // EPERM Error::EPERM => -1, // EPERM
@ -92,6 +105,8 @@ impl Error {
Error::EISDIR => -21, // EISDIR Error::EISDIR => -21, // EISDIR
Error::EEXIST => -17, // EEXIST Error::EEXIST => -17, // EEXIST
Error::ENOTEMPTY => -39, // ENOTEMPTY Error::ENOTEMPTY => -39, // ENOTEMPTY
Error::ECHILD => -10, // ECHILD
Error::ESRCH => -3, // ESRCH
} }
} }
} }
@ -110,6 +125,9 @@ impl fmt::Display for Error {
Error::WouldBlock => write!(f, "Resource temporarily unavailable"), Error::WouldBlock => write!(f, "Resource temporarily unavailable"),
Error::Device => write!(f, "Device error"), Error::Device => write!(f, "Device error"),
Error::Generic => write!(f, "Generic 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"),
// Linux errno variants // Linux errno variants
Error::EPERM => write!(f, "Operation not permitted"), Error::EPERM => write!(f, "Operation not permitted"),
@ -126,6 +144,8 @@ impl fmt::Display for Error {
Error::EISDIR => write!(f, "Is a directory"), Error::EISDIR => write!(f, "Is a directory"),
Error::EEXIST => write!(f, "File exists"), Error::EEXIST => write!(f, "File exists"),
Error::ENOTEMPTY => write!(f, "Directory not empty"), Error::ENOTEMPTY => write!(f, "Directory not empty"),
Error::ECHILD => write!(f, "No child processes"),
Error::ESRCH => write!(f, "No such process"),
} }
} }
} }

View File

@ -2,8 +2,8 @@
//! Directory entry (dentry) abstraction - Linux compatible //! Directory entry (dentry) abstraction - Linux compatible
use crate::error::{Error, Result}; use crate::error::Result;
use crate::sync::{Arc, Mutex, RwLock}; use crate::sync::{Arc, Mutex};
use alloc::{string::String, vec::Vec, format}; // Add format macro use alloc::{string::String, vec::Vec, format}; // Add format macro
use core::sync::atomic::{AtomicU32, Ordering}; use core::sync::atomic::{AtomicU32, Ordering};

View File

@ -3,8 +3,7 @@
//! Inode abstraction - Linux compatible //! Inode abstraction - Linux compatible
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::types::*; use crate::sync::{Arc, Mutex};
use crate::sync::{Arc, Mutex, RwLock};
use crate::device::DeviceNumber; use crate::device::DeviceNumber;
use crate::time::{TimeSpec, get_current_time}; use crate::time::{TimeSpec, get_current_time};
use alloc::string::String; use alloc::string::String;

View File

@ -18,14 +18,11 @@ pub mod devfs;
pub mod mode; // Add mode module pub mod mode; // Add mode module
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::types::*; use crate::sync::{Arc, Mutex};
use crate::sync::{Arc, Mutex, RwLock};
use crate::memory::{UserPtr, UserSlicePtr}; use crate::memory::{UserPtr, UserSlicePtr};
use crate::device::DeviceNumber;
use alloc::vec::Vec; use alloc::vec::Vec;
use alloc::string::String; use alloc::string::String;
use alloc::collections::BTreeMap; use alloc::collections::BTreeMap;
use core::fmt;
pub use file::*; pub use file::*;
pub use inode::*; pub use inode::*;

View File

@ -3,7 +3,7 @@
//! VFS mount abstraction - Linux compatible //! VFS mount abstraction - Linux compatible
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::sync::{Arc, Mutex, RwLock}; use crate::sync::{Arc, Mutex};
use alloc::{string::String, vec::Vec, format}; // Add format macro use alloc::{string::String, vec::Vec, format}; // Add format macro
use core::sync::atomic::{AtomicU32, Ordering}; use core::sync::atomic::{AtomicU32, Ordering};
@ -215,7 +215,7 @@ pub fn do_mount(
let mount = Arc::new(VfsMount::new(sb, dir_name, flags)?); let mount = Arc::new(VfsMount::new(sb, dir_name, flags)?);
let ns = get_init_ns(); let ns = get_init_ns();
let mut ns = ns.lock(); let ns = ns.lock();
ns.add_mount(mount); ns.add_mount(mount);
crate::console::print_info(&format!("Mounted {} on {} (type {})\n", dev_name, dir_name, type_name)); crate::console::print_info(&format!("Mounted {} on {} (type {})\n", dev_name, dir_name, type_name));
@ -225,7 +225,7 @@ pub fn do_mount(
/// Unmount a filesystem /// Unmount a filesystem
pub fn do_umount(dir_name: &str, flags: u32) -> Result<()> { pub fn do_umount(dir_name: &str, flags: u32) -> Result<()> {
let ns = get_init_ns(); let ns = get_init_ns();
let mut ns = ns.lock(); let ns = ns.lock();
if let Some(mount) = ns.remove_mount(dir_name) { if let Some(mount) = ns.remove_mount(dir_name) {
mount.mntput(); mount.mntput();
@ -281,7 +281,7 @@ pub fn do_remount(dir_name: &str, flags: u32, data: Option<&str>) -> Result<()>
/// Bind mount - create a bind mount /// Bind mount - create a bind mount
pub fn do_bind_mount(old_path: &str, new_path: &str, flags: u32) -> Result<()> { pub fn do_bind_mount(old_path: &str, new_path: &str, flags: u32) -> Result<()> {
let ns = get_init_ns(); let ns = get_init_ns();
let mut ns = ns.lock(); let ns = ns.lock();
if let Some(old_mount) = ns.find_mount(old_path) { 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)?); let new_mount = Arc::new(VfsMount::new(old_mount.mnt_sb.clone(), new_path, flags | super::super_block::MS_BIND)?);

View File

@ -4,9 +4,7 @@
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::sync::Arc; use crate::sync::Arc;
use crate::memory::{UserPtr, UserSlicePtr}; use crate::memory::UserSlicePtr;
use alloc::string::String;
use alloc::vec::Vec;
/// Address space operations trait - similar to Linux address_space_operations /// Address space operations trait - similar to Linux address_space_operations
pub trait AddressSpaceOperations: Send + Sync { pub trait AddressSpaceOperations: Send + Sync {

View File

@ -2,8 +2,8 @@
//! Superblock abstraction - Linux compatible //! Superblock abstraction - Linux compatible
use crate::error::{Error, Result}; use crate::error::Result;
use crate::sync::{Arc, Mutex, RwLock}; use crate::sync::{Arc, Mutex};
use crate::device::DeviceNumber; use crate::device::DeviceNumber;
use alloc::string::String; use alloc::string::String;
use alloc::vec::Vec; use alloc::vec::Vec;

View File

@ -2,7 +2,6 @@
//! Kernel initialization //! Kernel initialization
use crate::error::Result;
use crate::{info, error}; use crate::{info, error};
/// Early kernel initialization /// Early kernel initialization
@ -58,6 +57,33 @@ pub fn main_init() -> ! {
} }
info!("VFS initialized"); info!("VFS initialized");
// Initialize process management
if let Err(e) = crate::process::init_process_management() {
error!("Failed to initialize process management: {}", e);
panic!("Process management initialization failed");
}
info!("Process management initialized");
// Initialize system calls
if let Err(e) = crate::syscalls::init_syscalls() {
error!("Failed to initialize syscalls: {}", e);
panic!("Syscall initialization failed");
}
info!("System calls initialized");
// Initialize time management
if let Err(e) = crate::time::init_time() {
error!("Failed to initialize time management: {}", e);
panic!("Time management initialization failed");
}
info!("Time management initialized");
// TODO: Initialize drivers
// init_drivers();
// TODO: Start kernel threads
// start_kernel_threads();
info!("Kernel initialization completed"); info!("Kernel initialization completed");
info!("Starting idle loop"); info!("Starting idle loop");

View File

@ -4,9 +4,9 @@
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::sync::Spinlock; use crate::sync::Spinlock;
use crate::types::Irq; use alloc::{collections::BTreeMap, boxed::Box}; // Add Box import
use alloc::{vec::Vec, collections::BTreeMap, boxed::Box}; // Add Box import
use core::fmt; use core::fmt;
use core::arch::asm;
/// IRQ flags - compatible with Linux kernel /// IRQ flags - compatible with Linux kernel
pub mod irq_flags { pub mod irq_flags {
@ -155,6 +155,7 @@ impl InterruptSubsystem {
self.descriptors.get_mut(&irq) self.descriptors.get_mut(&irq)
} }
#[allow(dead_code)]
fn get_descriptor(&self, irq: u32) -> Option<&IrqDescriptor> { fn get_descriptor(&self, irq: u32) -> Option<&IrqDescriptor> {
self.descriptors.get(&irq) self.descriptors.get(&irq)
} }
@ -284,8 +285,8 @@ pub fn free_irq(irq: u32, dev_id: *mut u8) -> Result<()> {
if let Some(desc) = subsystem.get_descriptor_mut(irq) { if let Some(desc) = subsystem.get_descriptor_mut(irq) {
// Remove action with matching dev_id // Remove action with matching dev_id
let mut prev: Option<&mut Box<IrqAction>> = None; let prev: Option<&mut Box<IrqAction>> = None;
let mut current = &mut desc.action; let current = &mut desc.action;
let mut found = false; let mut found = false;
// Handle first element specially // Handle first element specially
@ -365,59 +366,39 @@ pub fn disable_irq(irq: u32) -> Result<()> {
} }
} }
/// Handle an interrupt - called from low-level interrupt handlers /// Register an interrupt handler at a specific vector
pub fn handle_interrupt(irq: u32) { pub fn register_interrupt_handler(vector: u32, handler: usize) -> Result<()> {
let mut subsystem = INTERRUPT_SUBSYSTEM.lock(); // TODO: Implement IDT (Interrupt Descriptor Table) setup
// For now, this is a placeholder that would:
// 1. Set up IDT entry for the given vector
// 2. Install the handler function
// 3. Configure interrupt gate type and privilege level
if let Some(desc) = subsystem.get_descriptor_mut(irq) { crate::info!("Registering interrupt handler at vector 0x{:x} -> 0x{:x}", vector, handler);
desc.irq_count += 1;
if !desc.is_enabled() { // In a real implementation, this would configure the IDT
// Interrupt is disabled, shouldn't happen // For x86_64, this involves setting up interrupt gates in the IDT
crate::warn!("Received disabled interrupt {}", irq); Ok(())
return;
} }
// Call all handlers in the action chain /// System call interrupt handler
let mut current = desc.action.as_ref(); #[no_mangle]
let mut handled = false; pub extern "C" fn syscall_handler() {
// TODO: Get syscall arguments from registers
// TODO: Call syscall dispatcher
// TODO: Return result in register
while let Some(action) = current { // For now, just a placeholder
let result = (action.handler)(irq, action.dev_id.as_ptr()); unsafe {
match result { asm!("iretq", options(noreturn));
IrqReturn::Handled => {
handled = true;
}
IrqReturn::WakeThread => {
handled = true;
// TODO: Wake threaded interrupt handler
}
IrqReturn::None => {
// Handler didn't handle this interrupt
}
}
current = action.next.as_ref();
}
if !handled {
desc.irqs_unhandled += 1;
if desc.irqs_unhandled > 100 {
crate::warn!("Too many unhandled interrupts on IRQ {}", irq);
}
}
} else {
crate::warn!("Spurious interrupt {}", irq);
} }
} }
/// Get interrupt statistics /// Install syscall interrupt handler
pub fn get_irq_stats() -> Vec<(u32, &'static str, u64, u64)> { pub fn install_syscall_handler() -> Result<()> {
let subsystem = INTERRUPT_SUBSYSTEM.lock(); // Install at interrupt vector 0x80 (traditional Linux syscall vector)
let mut stats = Vec::new(); register_interrupt_handler(0x80, syscall_handler as usize)?;
for (irq, desc) in &subsystem.descriptors { // TODO: Also set up SYSCALL/SYSRET for x86_64
stats.push((*irq, desc.name, desc.irq_count, desc.irqs_unhandled)); Ok(())
}
stats
} }

View File

@ -36,11 +36,11 @@ pub mod process;
pub mod scheduler; pub mod scheduler;
pub mod sync; pub mod sync;
pub mod syscall; pub mod syscall;
pub mod syscalls; // New syscall infrastructure
pub mod task; pub mod task;
pub mod time; pub mod time;
pub mod types; pub mod types;
use core::panic::PanicInfo;
/// Kernel version information /// Kernel version information
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = env!("CARGO_PKG_VERSION");

View File

@ -1,19 +1,153 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
//! Heap allocator implementation //! Memory allocator implementation - Enhanced with buddy allocator
use crate::memory::ALLOCATOR; use crate::memory::ALLOCATOR;
use crate::types::{VirtAddr, PAGE_SIZE}; use crate::types::{VirtAddr, PhysAddr, PAGE_SIZE};
use crate::error::Result; use crate::error::{Error, Result};
use crate::sync::Spinlock;
use alloc::vec::Vec;
/// 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) /// Heap start address (will be set during initialization)
static mut HEAP_START: usize = 0; static mut HEAP_START: usize = 0;
static mut HEAP_SIZE: usize = 0; static mut HEAP_SIZE: usize = 0;
/// Initialize the heap allocator /// Initialize the allocators
pub fn init() -> Result<()> { pub fn init() -> Result<()> {
// TODO: Get heap region from memory map // Initialize heap allocator
// For now, use a fixed region
let heap_start = 0x_4444_4444_0000; let heap_start = 0x_4444_4444_0000;
let heap_size = 100 * 1024; // 100 KB let heap_size = 100 * 1024; // 100 KB
@ -23,6 +157,16 @@ pub fn init() -> Result<()> {
ALLOCATOR.lock().init(heap_start as *mut u8, heap_size); ALLOCATOR.lock().init(heap_start as *mut u8, 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(()) Ok(())
} }
@ -30,3 +174,42 @@ pub fn init() -> Result<()> {
pub fn heap_stats() -> (usize, usize) { pub fn heap_stats() -> (usize, usize) {
unsafe { (HEAP_START, HEAP_SIZE) } 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
}
}

View File

@ -12,7 +12,6 @@ pub use page::Page;
pub use crate::types::{PhysAddr, VirtAddr, Pfn}; // Re-export from types pub use crate::types::{PhysAddr, VirtAddr, Pfn}; // Re-export from types
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use core::alloc::{GlobalAlloc, Layout};
use linked_list_allocator::LockedHeap; use linked_list_allocator::LockedHeap;
/// GFP (Get Free Pages) flags - compatible with Linux kernel /// GFP (Get Free Pages) flags - compatible with Linux kernel

View File

@ -6,7 +6,7 @@ use crate::types::{Pid, Tid, Uid, Gid};
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::sync::Spinlock; use crate::sync::Spinlock;
use crate::memory::VirtAddr; use crate::memory::VirtAddr;
use alloc::{string::String, vec::Vec, collections::BTreeMap}; use alloc::{string::{String, ToString}, vec::Vec, collections::BTreeMap};
use core::sync::atomic::{AtomicU32, Ordering}; use core::sync::atomic::{AtomicU32, Ordering};
/// Process state - compatible with Linux kernel /// Process state - compatible with Linux kernel
@ -71,6 +71,67 @@ impl Process {
pub fn is_running(&self) -> bool { pub fn is_running(&self) -> bool {
self.state == ProcessState::Running 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 /// Thread structure - Linux-compatible
@ -185,6 +246,7 @@ impl ProcessTable {
self.processes.get_mut(&pid) self.processes.get_mut(&pid)
} }
#[allow(dead_code)]
fn remove_process(&mut self, pid: Pid) -> Option<Process> { fn remove_process(&mut self, pid: Pid) -> Option<Process> {
let process = self.processes.remove(&pid); let process = self.processes.remove(&pid);
if self.current_process == Some(pid) { if self.current_process == Some(pid) {
@ -224,14 +286,24 @@ pub fn create_process(name: String, uid: Uid, gid: Gid) -> Result<Pid> {
Ok(pid) Ok(pid)
} }
/// Get current process /// Get current process PID
pub fn current_process() -> Option<Pid> { pub fn current_process_pid() -> Option<Pid> {
let table = PROCESS_TABLE.lock(); let table = PROCESS_TABLE.lock();
table.current_process 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 /// Get process by PID
pub fn get_process(pid: Pid) -> Option<Process> { pub fn find_process(pid: Pid) -> Option<Process> {
let table = PROCESS_TABLE.lock(); let table = PROCESS_TABLE.lock();
table.get_process(pid).cloned() table.get_process(pid).cloned()
} }
@ -254,6 +326,11 @@ pub fn list_processes() -> Vec<Pid> {
table.list_processes() table.list_processes()
} }
/// Initialize process management
pub fn init_process_management() -> Result<()> {
init()
}
/// Initialize the process subsystem /// Initialize the process subsystem
pub fn init() -> Result<()> { pub fn init() -> Result<()> {
// Create kernel process (PID 0) // Create kernel process (PID 0)

View File

@ -3,8 +3,7 @@
//! Task scheduler compatible with Linux kernel CFS (Completely Fair Scheduler) //! Task scheduler compatible with Linux kernel CFS (Completely Fair Scheduler)
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::process::{Process, Thread, ProcessState, ThreadContext}; use crate::types::Tid;
use crate::types::{Pid, Tid, Nanoseconds};
use crate::sync::Spinlock; use crate::sync::Spinlock;
use crate::time; use crate::time;
use alloc::{collections::{BTreeMap, VecDeque}, vec::Vec}; use alloc::{collections::{BTreeMap, VecDeque}, vec::Vec};

View File

@ -28,7 +28,7 @@ impl<T> Spinlock<T> {
} }
} }
pub fn lock(&self) -> SpinlockGuard<T> { pub fn lock(&self) -> SpinlockGuard<'_, T> {
while self.locked.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() { while self.locked.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() {
// Busy wait // Busy wait
while self.locked.load(Ordering::Relaxed) { while self.locked.load(Ordering::Relaxed) {
@ -39,7 +39,7 @@ impl<T> Spinlock<T> {
SpinlockGuard { lock: self } SpinlockGuard { lock: self }
} }
pub fn try_lock(&self) -> Option<SpinlockGuard<T>> { pub fn try_lock(&self) -> Option<SpinlockGuard<'_, T>> {
if self.locked.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed).is_ok() { if self.locked.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed).is_ok() {
Some(SpinlockGuard { lock: self }) Some(SpinlockGuard { lock: self })
} else { } else {

291
kernel/src/syscalls.rs Normal file
View File

@ -0,0 +1,291 @@
// SPDX-License-Identifier: GPL-2.0
//! System call interface - Linux compatible
use crate::error::{Error, Result};
use crate::types::Pid;
use crate::process::{current_process, find_process, allocate_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> {
// TODO: Implement fork
// 1. Allocate new PID
// 2. Copy current process
// 3. Set up copy-on-write memory
// 4. Add to scheduler
// 5. Return child PID to parent, 0 to child
let new_pid = allocate_pid();
// For now, just return the new PID
Ok(new_pid.0 as u64)
}
pub fn sys_execve(filename: u64, argv: u64, envp: u64) -> Result<u64> {
// TODO: Implement execve
// 1. Load program from filesystem
// 2. Set up new memory layout
// 3. Parse arguments and environment
// 4. Set up initial stack
// 5. Jump to entry point
Err(Error::ENOSYS)
}
pub fn sys_exit(exit_code: i32) -> Result<u64> {
// TODO: Implement exit
// 1. Set process state to zombie
// 2. Free resources
// 3. Notify parent
// 4. Schedule next process
// This syscall doesn't return
panic!("Process exit with code {}", exit_code);
}
pub fn sys_wait4(pid: u64, status: u64, options: u64, rusage: u64) -> Result<u64> {
// TODO: Implement wait4
// 1. Find child process
// 2. Block until child exits
// 3. Return child PID and status
Err(Error::ECHILD)
}
pub fn sys_kill(pid: i32, signal: i32) -> Result<u64> {
// TODO: Implement kill
// 1. Find target process
// 2. Send signal
// 3. Wake up process if needed
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> {
// TODO: Implement read
// 1. Get file from file descriptor table
// 2. Read from file
// 3. Copy to user buffer
Err(Error::ENOSYS)
}
pub fn sys_write(fd: i32, buf: u64, count: u64) -> Result<u64> {
// TODO: Implement write
// 1. Get file from file descriptor table
// 2. Copy from user buffer
// 3. Write to file
if fd == 1 || fd == 2 { // stdout or stderr
// For now, just return the count as if we wrote to console
Ok(count)
} else {
Err(Error::EBADF)
}
}
pub fn sys_open(filename: u64, flags: i32, mode: u32) -> Result<u64> {
// TODO: Implement open
// 1. Copy filename from user space
// 2. Open file in VFS
// 3. Allocate file descriptor
// 4. Add to process file table
Err(Error::ENOSYS)
}
pub fn sys_close(fd: i32) -> Result<u64> {
// TODO: Implement close
// 1. Get file from file descriptor table
// 2. Remove from table
// 3. Close file
Err(Error::ENOSYS)
}
/// Memory management syscalls
pub fn sys_mmap(addr: u64, length: u64, prot: i32, flags: i32, fd: i32, offset: i64) -> Result<u64> {
// TODO: Implement mmap
// 1. Validate parameters
// 2. Find free virtual memory region
// 3. Create VMA
// 4. Set up page tables
// 5. Return mapped address
Err(Error::ENOSYS)
}
pub fn sys_munmap(addr: u64, length: u64) -> Result<u64> {
// TODO: Implement munmap
// 1. Find VMA containing address
// 2. Unmap pages
// 3. Free physical memory
// 4. Remove VMA
Err(Error::ENOSYS)
}
pub fn sys_brk(addr: u64) -> Result<u64> {
// TODO: Implement brk
// 1. Get current heap end
// 2. Validate new address
// 3. Expand or shrink heap
// 4. Return new heap end
Err(Error::ENOSYS)
}
/// 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<()> {
// TODO: Set up syscall entry point in IDT/MSR
// For x86_64, this would involve setting up the SYSCALL instruction
Ok(())
}

View File

@ -3,7 +3,7 @@
//! Time management compatible with Linux kernel //! Time management compatible with Linux kernel
use crate::error::Result; use crate::error::Result;
use crate::types::{Nanoseconds, Microseconds, Milliseconds, Seconds, Jiffies}; use crate::types::Jiffies;
use core::sync::atomic::{AtomicU64, Ordering}; use core::sync::atomic::{AtomicU64, Ordering};
use alloc::vec::Vec; // Add Vec import use alloc::vec::Vec; // Add Vec import
@ -121,6 +121,21 @@ pub fn init() -> Result<()> {
Ok(()) Ok(())
} }
/// 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 (placeholder) /// Read hardware clock (placeholder)
fn read_hardware_clock() -> u64 { fn read_hardware_clock() -> u64 {
// TODO: Read from actual hardware clock (RTC, TSC, etc.) // TODO: Read from actual hardware clock (RTC, TSC, etc.)
@ -282,7 +297,10 @@ fn get_timer_wheel() -> &'static Spinlock<TimerWheel> {
TIMER_WHEEL_INIT.store(true, Ordering::Release); TIMER_WHEEL_INIT.store(true, Ordering::Release);
} }
unsafe { TIMER_WHEEL_STORAGE.as_ref().unwrap() } #[allow(static_mut_refs)]
unsafe {
TIMER_WHEEL_STORAGE.as_ref().unwrap()
}
} }
/// Add a timer to the system /// Add a timer to the system