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

14
drivers/Cargo.toml Archivo normal
Ver fichero

@@ -0,0 +1,14 @@
[package]
name = "drivers"
version = "0.1.0"
edition = "2021"
authors = ["Rust Kernel Contributors"]
description = "Kernel drivers"
license = "GPL-2.0"
[lib]
name = "drivers"
crate-type = ["rlib"]
[dependencies]
kernel = { path = "../kernel" }

352
drivers/src/keyboard.rs Archivo normal
Ver fichero

@@ -0,0 +1,352 @@
// SPDX-License-Identifier: GPL-2.0
//! PS/2 Keyboard driver
use alloc::{collections::VecDeque, string::String, vec::Vec};
use kernel::arch::x86_64::port::{inb, outb};
use kernel::device::{CharDevice, Device, DeviceType, FileOperations};
use kernel::error::{Error, Result};
use kernel::interrupt::{register_interrupt_handler, IrqHandler};
use kernel::sync::{Arc, Spinlock};
/// 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> {
// Implement keyboard-specific ioctl commands
match cmd {
0x4B01 => {
// KDGKBMODE - get keyboard mode
crate::info!("Getting keyboard mode");
Ok(0) // Return raw mode
}
0x4B02 => {
// KDSKBMODE - set keyboard mode
crate::info!("Setting keyboard mode to {}", arg);
Ok(0)
}
0x4B03 => {
// KDGKBENT - get keyboard entry
crate::info!("Getting keyboard entry");
Ok(0)
}
_ => 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
// Register device in device filesystem
crate::info!("Keyboard device registered in devfs");
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)
}

16
drivers/src/lib.rs Archivo normal
Ver fichero

@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel drivers library
//!
//! This crate contains various kernel drivers for the Rust kernel.
#![no_std]
extern crate alloc;
pub mod keyboard; // Keyboard driver
pub mod mem;
pub mod ramdisk;
pub mod rtl8139;
pub mod serial; // Serial driver
pub use ramdisk::*;

186
drivers/src/mem.rs Archivo normal
Ver fichero

@@ -0,0 +1,186 @@
// SPDX-License-Identifier: GPL-2.0
//! Null, zero, and full device drivers
//! Based on Linux drivers/char/mem.c
#![no_std]
#![no_main]
use kernel::device::{CharDevice, File, FileOperations, Inode, VMA};
use kernel::driver::CharDriverOps;
use kernel::prelude::*;
/// Null device driver (/dev/null)
#[derive(Debug)]
struct NullDevice;
impl FileOperations for NullDevice {
fn open(&self, _inode: &Inode, _file: &mut File) -> Result<()> {
Ok(())
}
fn release(&self, _inode: &Inode, _file: &mut File) -> Result<()> {
Ok(())
}
fn read(&self, _file: &mut File, _buf: &mut [u8], _offset: u64) -> Result<usize> {
// Reading from /dev/null always returns EOF
Ok(0)
}
fn write(&self, _file: &mut File, buf: &[u8], _offset: u64) -> Result<usize> {
// Writing to /dev/null always succeeds and discards data
Ok(buf.len())
}
fn ioctl(&self, _file: &mut File, _cmd: u32, _arg: usize) -> Result<usize> {
Err(Error::NotSupported)
}
fn mmap(&self, _file: &mut File, _vma: &mut VMA) -> Result<()> {
Err(Error::NotSupported)
}
}
/// Zero device driver (/dev/zero)
#[derive(Debug)]
struct ZeroDevice;
impl FileOperations for ZeroDevice {
fn open(&self, _inode: &Inode, _file: &mut File) -> Result<()> {
Ok(())
}
fn release(&self, _inode: &Inode, _file: &mut File) -> Result<()> {
Ok(())
}
fn read(&self, _file: &mut File, buf: &mut [u8], _offset: u64) -> Result<usize> {
// Reading from /dev/zero returns zeros
for byte in buf.iter_mut() {
*byte = 0;
}
Ok(buf.len())
}
fn write(&self, _file: &mut File, buf: &[u8], _offset: u64) -> Result<usize> {
// Writing to /dev/zero always succeeds and discards data
Ok(buf.len())
}
fn ioctl(&self, _file: &mut File, _cmd: u32, _arg: usize) -> Result<usize> {
Err(Error::NotSupported)
}
fn mmap(&self, _file: &mut File, vma: &mut VMA) -> Result<()> {
// /dev/zero can be mmap'd to get zero-filled pages
// Implement proper mmap support for zero device
crate::info!(
"Mapping zero-filled pages at 0x{:x}",
vma.vm_start.as_usize()
);
// In a real implementation, this would:
// 1. Set up anonymous pages filled with zeros
// 2. Configure page fault handler to provide zero pages on demand
// 3. Mark pages as copy-on-write if needed
// For now, just log the operation
Ok(())
}
}
/// Full device driver (/dev/full)
#[derive(Debug)]
struct FullDevice;
impl FileOperations for FullDevice {
fn open(&self, _inode: &Inode, _file: &mut File) -> Result<()> {
Ok(())
}
fn release(&self, _inode: &Inode, _file: &mut File) -> Result<()> {
Ok(())
}
fn read(&self, _file: &mut File, buf: &mut [u8], _offset: u64) -> Result<usize> {
// Reading from /dev/full returns zeros
for byte in buf.iter_mut() {
*byte = 0;
}
Ok(buf.len())
}
fn write(&self, _file: &mut File, _buf: &[u8], _offset: u64) -> Result<usize> {
// Writing to /dev/full always fails with "no space left"
Err(Error::OutOfMemory) // ENOSPC equivalent
}
fn ioctl(&self, _file: &mut File, _cmd: u32, _arg: usize) -> Result<usize> {
Err(Error::NotSupported)
}
fn mmap(&self, _file: &mut File, _vma: &mut VMA) -> Result<()> {
Err(Error::NotSupported)
}
}
/// Memory devices module
struct MemoryDevicesModule {
null_major: u32,
zero_major: u32,
full_major: u32,
}
impl kernel::module::Module for MemoryDevicesModule {
fn init(_module: &'static kernel::module::ThisModule) -> Result<Self> {
info!("Memory devices module initializing...");
// Register /dev/null (major 1, minor 3)
let null_major = kernel::device::register_chrdev(
1,
String::from("null"),
Box::new(NullDevice),
)?;
// Register /dev/zero (major 1, minor 5)
let zero_major = kernel::device::register_chrdev(
1,
String::from("zero"),
Box::new(ZeroDevice),
)?;
// Register /dev/full (major 1, minor 7)
let full_major = kernel::device::register_chrdev(
1,
String::from("full"),
Box::new(FullDevice),
)?;
info!(
"Memory devices registered: null={}, zero={}, full={}",
null_major, zero_major, full_major
);
Ok(MemoryDevicesModule {
null_major,
zero_major,
full_major,
})
}
fn exit(_module: &'static kernel::module::ThisModule) {
info!("Memory devices module exiting");
// Unregister character devices
kernel::device::unregister_chrdev(1).ok();
}
}
module! {
type: MemoryDevicesModule,
name: "mem_devices",
author: "Rust Kernel Contributors",
description: "Memory devices (/dev/null, /dev/zero, /dev/full)",
license: "GPL-2.0",
}

187
drivers/src/ramdisk.rs Archivo normal
Ver fichero

@@ -0,0 +1,187 @@
// SPDX-License-Identifier: GPL-2.0
//! RAM disk block device driver
//! Based on Linux drivers/block/brd.c
#![no_std]
#![no_main]
use kernel::device::{BlockDevice, Device, DeviceType};
use kernel::driver::{BlockDriverOps, Driver};
use kernel::memory::{AllocFlags, GFP_KERNEL};
use kernel::prelude::*;
/// RAM disk device
struct RamDisk {
size: u64, // Size in bytes
block_size: u32, // Block size in bytes
data: Vec<u8>, // Actual storage
}
impl RamDisk {
fn new(size: u64, block_size: u32) -> Result<Self> {
let mut data = Vec::new();
data.try_reserve(size as usize)?;
data.resize(size as usize, 0);
Ok(Self {
size,
block_size,
data,
})
}
fn get_block_count(&self) -> u64 {
self.size / self.block_size as u64
}
}
impl BlockDriverOps for RamDisk {
fn read_block(&self, block: u64, buffer: &mut [u8]) -> Result<usize> {
if block >= self.get_block_count() {
return Err(Error::InvalidArgument);
}
let offset = (block * self.block_size as u64) as usize;
let size = core::cmp::min(buffer.len(), self.block_size as usize);
if offset + size > self.data.len() {
return Err(Error::InvalidArgument);
}
buffer[..size].copy_from_slice(&self.data[offset..offset + size]);
Ok(size)
}
fn write_block(&self, block: u64, buffer: &[u8]) -> Result<usize> {
if block >= self.get_block_count() {
return Err(Error::InvalidArgument);
}
let offset = (block * self.block_size as u64) as usize;
let size = core::cmp::min(buffer.len(), self.block_size as usize);
if offset + size > self.data.len() {
return Err(Error::InvalidArgument);
}
// This is a bit unsafe due to the immutable reference, but for simplicity...
// In a real implementation, we'd use proper interior mutability
unsafe {
let data_ptr = self.data.as_ptr() as *mut u8;
let dest = core::slice::from_raw_parts_mut(data_ptr.add(offset), size);
dest.copy_from_slice(&buffer[..size]);
}
Ok(size)
}
fn get_block_size(&self) -> u32 {
self.block_size
}
fn get_total_blocks(&self) -> u64 {
self.get_block_count()
}
fn flush(&self) -> Result<()> {
// RAM disk doesn't need flushing
Ok(())
}
}
/// RAM disk driver
struct RamDiskDriver {
name: &'static str,
}
impl RamDiskDriver {
fn new() -> Self {
Self { name: "ramdisk" }
}
}
impl Driver for RamDiskDriver {
fn name(&self) -> &str {
self.name
}
fn probe(&self, device: &mut Device) -> Result<()> {
info!("RAM disk driver probing device: {}", device.name());
// Create a 16MB RAM disk with 4KB blocks
let ramdisk = RamDisk::new(16 * 1024 * 1024, 4096)?;
info!(
"Created RAM disk: {} blocks of {} bytes each",
ramdisk.get_total_blocks(),
ramdisk.get_block_size()
);
device.set_private_data(ramdisk);
Ok(())
}
fn remove(&self, device: &mut Device) -> Result<()> {
info!("RAM disk driver removing device: {}", device.name());
Ok(())
}
}
/// RAM disk module
struct RamDiskModule {
driver: RamDiskDriver,
device_created: bool,
}
impl kernel::module::Module for RamDiskModule {
fn init(_module: &'static kernel::module::ThisModule) -> Result<Self> {
info!("RAM disk module initializing...");
let driver = RamDiskDriver::new();
// Register the driver
kernel::driver::register_driver(Box::new(driver))?;
// Create a RAM disk device
let mut device = Device::new(
String::from("ram0"),
DeviceType::Block,
1, // major number for RAM disk
0, // minor number
);
// Set up the driver for this device
let ramdisk_driver = RamDiskDriver::new();
device.set_driver(Box::new(ramdisk_driver))?;
// Register the device
kernel::device::register_device(device)?;
info!("RAM disk device created and registered");
Ok(RamDiskModule {
driver: RamDiskDriver::new(),
device_created: true,
})
}
fn exit(_module: &'static kernel::module::ThisModule) {
info!("RAM disk module exiting");
if self.device_created {
kernel::device::unregister_device("ram0").ok();
}
kernel::driver::unregister_driver("ramdisk").ok();
}
}
module! {
type: RamDiskModule,
name: "ramdisk",
author: "Rust Kernel Contributors",
description: "RAM disk block device driver",
license: "GPL-2.0",
}

302
drivers/src/rtl8139.rs Archivo normal
Ver fichero

@@ -0,0 +1,302 @@
// SPDX-License-Identifier: GPL-2.0
//! RTL8139 Network Driver
use alloc::boxed::Box;
use alloc::string::ToString;
use core::ptr;
use kernel::driver::{Driver, PciDevice, PciDeviceId, PciDriver};
use kernel::error::{Error, Result};
use kernel::memory::{allocator, vmalloc};
use kernel::network::NetworkInterface;
use kernel::pci_driver;
use kernel::types::PhysAddr;
const REG_MAC0: u16 = 0x00;
const REG_MAR0: u16 = 0x08;
const REG_RBSTART: u16 = 0x30;
const REG_CMD: u16 = 0x37;
const REG_IMR: u16 = 0x3C;
const REG_ISR: u16 = 0x3E;
const REG_RCR: u16 = 0x44;
const REG_CONFIG1: u16 = 0x52;
const REG_TX_STATUS_0: u16 = 0x10;
const REG_TX_START_0: u16 = 0x20;
const CMD_RESET: u8 = 0x10;
const CMD_RX_ENB: u8 = 0x08;
const CMD_TX_ENB: u8 = 0x04;
const IMR_ROK: u16 = 1 << 0;
const IMR_TOK: u16 = 1 << 2;
const RCR_AAP: u32 = 1 << 0; // AcceptAllPackets
const RCR_APM: u32 = 1 << 1; // AcceptPhysicalMatch
const RCR_AM: u32 = 1 << 2; // AcceptMulticast
const RCR_AB: u32 = 1 << 3; // AcceptBroadcast
const RCR_WRAP: u32 = 1 << 7;
#[derive(Debug)]
struct Rtl8139Device {
mmio_base: usize,
mac: [u8; 6],
rx_buffer: *mut u8,
tx_buffer: *mut u8,
rx_buffer_pos: usize,
tx_cur: usize,
up: bool,
}
impl Rtl8139Device {
fn new(mmio_base: usize) -> Self {
Self {
mmio_base,
mac: [0; 6],
rx_buffer: ptr::null_mut(),
tx_buffer: ptr::null_mut(),
rx_buffer_pos: 0,
tx_cur: 0,
up: false,
}
}
fn read8(&self, offset: u16) -> u8 {
unsafe { ptr::read_volatile((self.mmio_base + offset as usize) as *const u8) }
}
fn write8(&self, offset: u16, val: u8) {
unsafe { ptr::write_volatile((self.mmio_base + offset as usize) as *mut u8, val) }
}
fn read16(&self, offset: u16) -> u16 {
unsafe { ptr::read_volatile((self.mmio_base + offset as usize) as *const u16) }
}
fn write16(&self, offset: u16, val: u16) {
unsafe { ptr::write_volatile((self.mmio_base + offset as usize) as *mut u16, val) }
}
fn read32(&self, offset: u16) -> u32 {
unsafe { ptr::read_volatile((self.mmio_base + offset as usize) as *const u32) }
}
fn write32(&self, offset: u16, val: u32) {
unsafe { ptr::write_volatile((self.mmio_base + offset as usize) as *mut u32, val) }
}
}
#[derive(Debug)]
pub struct Rtl8139Driver;
impl NetworkInterface for Rtl8139Device {
fn name(&self) -> &str {
"eth0" // Or some other name
}
fn ip_address(&self) -> Option<kernel::network::Ipv4Address> {
None // This will be set by the network stack
}
fn mac_address(&self) -> kernel::network::MacAddress {
kernel::network::MacAddress::new(self.mac)
}
fn mtu(&self) -> u16 {
1500
}
fn is_up(&self) -> bool {
self.up
}
fn send_packet(&mut self, buffer: &kernel::network::NetworkBuffer) -> Result<()> {
let tx_status_reg = REG_TX_STATUS_0 + (self.tx_cur * 4) as u16;
// The transmit buffers are laid out contiguously in memory after the receive buffer.
let tx_buffer = unsafe { self.tx_buffer.add(self.tx_cur * 2048) };
// Copy the packet data to the transmit buffer.
unsafe {
ptr::copy_nonoverlapping(buffer.data().as_ptr(), tx_buffer, buffer.len());
}
// Write the buffer address to the transmit start register.
let dma_addr = PhysAddr::new(tx_buffer as usize);
self.write32(
REG_TX_START_0 + (self.tx_cur * 4) as u16,
dma_addr.as_usize() as u32,
);
// Write the packet size and flags to the transmit status register.
self.write32(tx_status_reg, buffer.len() as u32);
self.tx_cur = (self.tx_cur + 1) % 4;
Ok(())
}
fn receive_packet(&mut self) -> Result<Option<kernel::network::NetworkBuffer>> {
let isr = self.read16(REG_ISR);
if (isr & IMR_ROK) == 0 {
return Ok(None);
}
// Acknowledge the interrupt
self.write16(REG_ISR, IMR_ROK);
let rx_ptr = self.rx_buffer as *const u8;
let _header = unsafe {
ptr::read_unaligned(rx_ptr.add(self.rx_buffer_pos) as *const u16)
};
let len = unsafe {
ptr::read_unaligned(rx_ptr.add(self.rx_buffer_pos + 2) as *const u16)
};
let data_ptr = unsafe { rx_ptr.add(self.rx_buffer_pos + 4) };
let data = unsafe { core::slice::from_raw_parts(data_ptr, len as usize) };
// The data includes the Ethernet header.
if data.len() < 14 {
return Err(Error::InvalidArgument);
}
let dest_mac = kernel::network::MacAddress::new([
data[0], data[1], data[2], data[3], data[4], data[5],
]);
let src_mac = kernel::network::MacAddress::new([
data[6], data[7], data[8], data[9], data[10], data[11],
]);
let ethertype = u16::from_be_bytes([data[12], data[13]]);
let protocol = match ethertype {
0x0800 => kernel::network::ProtocolType::IPv4,
0x0806 => kernel::network::ProtocolType::ARP,
_ => return Ok(None), // Unknown protocol
};
let mut buffer = kernel::network::NetworkBuffer::from_data(data[14..].to_vec());
buffer.set_protocol(protocol);
buffer.set_mac_addresses(src_mac, dest_mac);
self.rx_buffer_pos = (self.rx_buffer_pos + len as usize + 4 + 3) & !3;
if self.rx_buffer_pos > 8192 {
self.rx_buffer_pos -= 8192;
}
self.write16(0x38, self.rx_buffer_pos as u16 - 16);
Ok(Some(buffer))
}
fn set_up(&mut self, up: bool) -> Result<()> {
if up {
self.write8(REG_CMD, CMD_RX_ENB | CMD_TX_ENB);
} else {
self.write8(REG_CMD, 0x00);
}
self.up = up;
Ok(())
}
fn set_mac_address(&mut self, _mac: kernel::network::MacAddress) -> Result<()> {
// Not supported
Err(Error::NotSupported)
}
}
impl Driver for Rtl8139Driver {
fn name(&self) -> &str {
"rtl8139"
}
fn probe(&self, _device: &mut kernel::device::Device) -> Result<()> {
// This will be called for a generic device.
// We are a PCI driver, so we'll do our work in pci_probe.
Ok(())
}
fn remove(&self, _device: &mut kernel::device::Device) -> Result<()> {
Ok(())
}
}
impl PciDriver for Rtl8139Driver {
fn pci_ids(&self) -> &[PciDeviceId] {
&[PciDeviceId::new(0x10EC, 0x8139)]
}
fn pci_probe(&self, pci_dev: &mut PciDevice) -> Result<()> {
kernel::info!("Probing rtl8139 device");
let bar0 = pci_dev.bars[0];
if bar0.is_io() {
return Err(Error::NotSupported);
}
let mmio_base = bar0.address;
kernel::info!("RTL8139 MMIO base: {:#x}", mmio_base);
let mmio_virt = vmalloc::vmap_phys(PhysAddr::new(mmio_base as usize), 0x100)?;
kernel::info!("RTL8139 MMIO mapped to: {:#x}", mmio_virt.as_usize());
let mut device = Rtl8139Device::new(mmio_virt.as_usize());
// Power on
device.write8(REG_CONFIG1, 0x00);
// Reset
device.write8(REG_CMD, CMD_RESET);
while (device.read8(REG_CMD) & CMD_RESET) != 0 {}
// Read MAC address
for i in 0..6 {
device.mac[i] = device.read8(REG_MAC0 + i as u16);
}
kernel::info!(
"RTL8139 MAC address: {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
device.mac[0],
device.mac[1],
device.mac[2],
device.mac[3],
device.mac[4],
device.mac[5]
);
// Allocate DMA buffers
let dma_pfn = allocator::alloc_pages(2, allocator::GfpFlags::DMA)?;
let dma_addr = dma_pfn.to_phys_addr();
device.rx_buffer = dma_addr.as_usize() as *mut u8;
device.tx_buffer = (dma_addr.as_usize() + 8192) as *mut u8;
// Initialize receive buffer
device.write32(REG_RBSTART, dma_addr.as_usize() as u32);
// Initialize transmit buffers
for i in 0..4 {
// Nothing to do here yet, we will set the buffer address when we send a packet.
}
// Enable RX and TX
device.write8(REG_CMD, CMD_RX_ENB | CMD_TX_ENB);
// Set RCR
device.write32(REG_RCR, RCR_AAP | RCR_APM | RCR_AM | RCR_AB | RCR_WRAP);
// Enable interrupts
device.write16(REG_IMR, IMR_TOK | IMR_ROK);
kernel::info!("RTL8139 device initialized");
let mut boxed_device = Box::new(device);
boxed_device.set_up(true)?;
kernel::network::add_network_interface("eth0".to_string(), boxed_device)?;
Ok(())
}
fn pci_remove(&self, _pci_dev: &mut PciDevice) -> Result<()> {
Ok(())
}
}
pci_driver!(Rtl8139Driver);

403
drivers/src/serial.rs Archivo normal
Ver fichero

@@ -0,0 +1,403 @@
// SPDX-License-Identifier: GPL-2.0
//! Serial console driver (16550 UART)
use alloc::{collections::VecDeque, string::String, vec::Vec};
use kernel::arch::x86_64::port::{inb, outb};
use kernel::device::{CharDevice, Device, DeviceType, FileOperations};
use kernel::error::{Error, Result};
use kernel::interrupt::{register_interrupt_handler, IrqHandler};
use kernel::sync::{Arc, Spinlock};
/// 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> {
// Implement serial-specific ioctl commands (baudrate, etc.)
match cmd {
0x5401 => {
// TCGETS - get terminal attributes
crate::info!("Getting terminal attributes");
Ok(0)
}
0x5402 => {
// TCSETS - set terminal attributes
crate::info!("Setting terminal attributes to {}", arg);
Ok(0)
}
0x540B => {
// TCFLSH - flush terminal I/O
crate::info!("Flushing terminal I/O");
self.flush();
Ok(0)
}
0x5415 => {
// TIOCGSERIAL - get serial port info
crate::info!("Getting serial port info");
Ok(0x3f8) // Return COM1 port address
}
0x541F => {
// TIOCGPTN - get pty number (not applicable for serial)
Err(Error::ENOTTY)
}
_ => {
crate::info!("Unknown ioctl command: 0x{:x}", cmd);
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)
}