Start stdin

This commit is contained in:
2026-03-13 11:15:52 +01:00
parent f67718c3fe
commit de6ef959ce
18 changed files with 347 additions and 72 deletions

38
src/cursor.rs Normal file
View File

@@ -0,0 +1,38 @@
use kernel_macros::include_bitmap_image;
use crate::draw::{Color, Draw};
pub const CURSOR_WIDTH: usize = 8;
pub const CURSOR_HEIGHT: usize = 10;
pub const CURSOR_SIZE: usize = (CURSOR_HEIGHT * CURSOR_WIDTH) / 8;
pub static CURSOR: [u8; CURSOR_SIZE] = include_bitmap_image! {"assets/cursor.png"};
pub fn draw_cursor<T: Draw>(drawer: &mut T, x: u16, y: u16) {
for i in 0..CURSOR_HEIGHT {
for j in 0..CURSOR_WIDTH {
let pos = i * CURSOR_WIDTH + j;
if CURSOR[pos / 8] & (1 << (pos % 8)) != 0 {
unsafe {
drawer.write_pixel_unsafe(
x.saturating_add(j as u16),
y.saturating_add(i as u16),
Color::WHITE,
)
};
}
}
}
}
pub fn clear_cursor<T: Draw>(drawer: &mut T, x: u16, y: u16) {
for i in 0..CURSOR_HEIGHT {
for j in 0..CURSOR_WIDTH {
unsafe {
drawer.write_pixel_unsafe(
x.saturating_add(j as u16),
y.saturating_add(i as u16),
Color::BLACK,
)
};
}
}
}

1
src/data_structures.rs Normal file
View File

@@ -0,0 +1 @@
pub mod circular_buffer;

View File

@@ -0,0 +1,55 @@
use core::mem::MaybeUninit;
#[derive(Debug)]
pub struct CircularBuffer<T, const SIZE: usize> {
buffer: [MaybeUninit<T>; SIZE],
head: usize,
tail: usize,
len: usize,
}
impl<T, const SIZE: usize> CircularBuffer<T, SIZE> {
pub const fn new() -> Self {
Self {
buffer: [const { MaybeUninit::uninit() }; SIZE],
head: 0,
tail: 0,
len: 0,
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn is_full(&self) -> bool {
self.len() == SIZE - 1
}
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
None
} else {
let out = core::mem::replace(&mut self.buffer[self.head], MaybeUninit::uninit());
self.head = (self.head + 1) % SIZE;
self.len -= 1;
// # Safety
// the queue is not empty and head points to a valid value
Some(unsafe { out.assume_init() })
}
}
pub fn push(&mut self, value: T) {
self.buffer[self.tail] = MaybeUninit::new(value);
if self.is_full() {
self.head = (self.head + 1) % SIZE;
} else {
self.len += 1;
}
self.tail = (self.tail + 1) % SIZE;
}
}

View File

@@ -1,4 +1,4 @@
use kernel_macros::include_font_plate;
use kernel_macros::include_bitmap_image;
/// 24-bit RGB color used by the framebuffer.
#[repr(transparent)]
@@ -121,4 +121,4 @@ pub const FONT_HEIGHT: usize = 13;
pub const FONTPLATE_WIDTH: usize = 32 * FONT_WIDTH;
pub const FONTPLATE_HEIGHT: usize = 3 * FONT_HEIGHT;
pub const FONTPLATE_SIZE: usize = FONTPLATE_WIDTH * FONTPLATE_HEIGHT / 8;
pub static FONTPLATE: [u8; FONTPLATE_SIZE] = include_font_plate! {"assets/fontplate.png"};
pub static FONTPLATE: [u8; FONTPLATE_SIZE] = include_bitmap_image! {"assets/fontplate.png"};

View File

@@ -149,6 +149,16 @@ unsafe extern "C" fn supervisor_trap_handler(
let vnode = current_process.fd_table.get_mut(&fd).unwrap();
vnode.write(buf).unwrap();
}
SysCall::Read => {
let fd = a1;
let buf =
unsafe { core::slice::from_raw_parts_mut(a2 as *mut u8, a3 as usize) };
let mut scheduler = SCHEDULER.lock();
let current_process = scheduler.get_current_process();
let vnode = current_process.fd_table.get_mut(&fd).unwrap();
vnode.read(buf).unwrap();
}
SysCall::Seek => {
let fd = a1;
let seek = match a2 {

View File

@@ -19,7 +19,7 @@ use embedded_alloc::LlffHeap as Heap;
use log::info;
use crate::{
draw::{Color, Draw},
cursor::{clear_cursor, draw_cursor},
io::init_log,
pci::{PciDeviceIterator, scan_virtio_devices},
riscv::enable_supervisor_interrupt,
@@ -28,14 +28,16 @@ use crate::{
vga::Vga,
virtio::{
Virtqueue,
input::{VirtioPciDriver, init_plic_pci},
input::{EventCodeValue, VirtioPciDriver, init_plic_pci},
},
virtual_fs::init_file_system,
virtual_fs::{FILE_SYSTEM, VirtualFileSystem, init_file_system},
};
extern crate alloc;
mod boot;
mod critical_section;
mod cursor;
mod data_structures;
mod draw;
mod fs;
mod interrupt;
@@ -72,11 +74,15 @@ static mut KBD_QUEUE: Virtqueue = unsafe { core::mem::zeroed() };
pub static mut KBD_DRIVER: VirtioPciDriver = unsafe {
VirtioPciDriver::new(
|event| {
let mut kbd_buffer = FILE_SYSTEM.open("/dev/input/keyboard".as_ref()).unwrap();
if event.is_key() {
let event = event.as_key_event();
println!("key, {:#?}", event);
if event.value == EventCodeValue::Pressed {
println!("event: {:#?}", event);
kbd_buffer.write(&[event.code as u8]).unwrap();
}
} else {
println!("key pressed, {:#?}", event);
// println!("key pressed, {:#?}", event);
}
},
&mut KBD_QUEUE,
@@ -92,7 +98,7 @@ pub static mut MOUSE_DRIVER: VirtioPciDriver = unsafe {
if event.is_relative() {
let event = event.as_relative_event();
vga::Vga.write_pixel_unsafe(MOUSE_POSITION.0, MOUSE_POSITION.1, Color::BLACK);
clear_cursor(&mut Vga, MOUSE_POSITION.0, MOUSE_POSITION.1);
match event.code {
virtio::input::EventCodeRelative::X => {
@@ -104,7 +110,7 @@ pub static mut MOUSE_DRIVER: VirtioPciDriver = unsafe {
_ => {}
}
vga::Vga.write_pixel_unsafe(MOUSE_POSITION.0, MOUSE_POSITION.1, Color::RED);
draw_cursor(&mut Vga, MOUSE_POSITION.0, MOUSE_POSITION.1);
// println!("mouse moved relatively, {:#?}", event);
} else {
@@ -122,8 +128,8 @@ pub extern "C" fn supervisor_mode_entry() {
HEAP_INITIALIZED.store(true, core::sync::atomic::Ordering::Relaxed);
init_log().unwrap();
Vga::init();
SCHEDULER.lock().init();
init_file_system();
SCHEDULER.lock().init();
}
info!("Hello World !");

View File

@@ -13,7 +13,6 @@ use alloc::{boxed::Box, format, string::String, vec::Vec};
use bffs::path::Path;
use goblin::elf::reloc::R_RISCV_RELATIVE;
use hashbrown::HashMap;
use log::info;
use shared::syscall::exit;
use crate::{
@@ -164,9 +163,7 @@ impl Scheduler {
let name = path.as_str();
// Open and read the binary file
info!("ue");
let mut bin = unsafe { FILE_SYSTEM.open(path).unwrap() };
info!("ue");
println!("Creating process");
let mut content: Vec<u8> = Vec::new();
bin.read_to_end(&mut content).unwrap();
@@ -300,6 +297,11 @@ impl Scheduler {
process.state = ProcessState::Activable;
process.entry = Some(code);
process.fd_table = HashMap::new();
process
.fd_table
.insert(0, FILE_SYSTEM.open("/dev/input/keyboard".into()).unwrap());
// Configure execution context
// a0 contains the pointer to the function to execute
process.ctx.a[0] = &raw const *process.entry.as_ref().unwrap_unchecked() as u64;

View File

@@ -8,7 +8,10 @@ use bffs::{
use hashbrown::HashMap;
use io::{IoBase, Read, Seek, Write};
use crate::{fs::Disk, tty::Tty, vga::Vga};
pub mod keyboard;
pub mod stdin;
use crate::{fs::Disk, tty::Tty, vga::Vga, virtual_fs::keyboard::KeyboardBuffer};
pub trait VirtualNode: IoBase<Error = ()> + Read + Write + Seek + Debug {}
@@ -53,6 +56,11 @@ pub unsafe fn init_file_system() {
unsafe {
FILE_SYSTEM.mount("/dev/fb0".into(), Box::new(VGAFileSystem));
FILE_SYSTEM.mount("/dev/tty0".into(), Box::new(Tty::new()));
FILE_SYSTEM.mount(
"/dev/input/keyboard".into(),
Box::new(KeyboardBuffer::new()),
);
// FILE_SYSTEM.mount("/dev/stdin".into(), Box::new(Stdin::new()));
}
}

View File

@@ -0,0 +1,85 @@
use core::cell::RefCell;
use alloc::boxed::Box;
use io::{IoBase, Read, Seek, Write};
use crate::{
data_structures::circular_buffer::CircularBuffer,
println,
virtual_fs::{VirtualFileSystem, VirtualNode},
};
pub const KEYBOARD_BUFFER_SIZE: usize = 4096; // 4Ko
#[derive(Debug)]
pub struct KeyboardBuffer {
buffer: RefCell<CircularBuffer<u8, KEYBOARD_BUFFER_SIZE>>,
}
impl KeyboardBuffer {
pub fn new() -> Self {
Self {
buffer: RefCell::new(CircularBuffer::new()),
}
}
}
#[derive(Debug)]
pub struct KeyboardBufferNode<'a> {
buffer: &'a KeyboardBuffer,
}
impl<'a> KeyboardBufferNode<'a> {
pub fn new(stdin: &'a KeyboardBuffer) -> Self {
Self { buffer: stdin }
}
}
impl VirtualFileSystem for KeyboardBuffer {
fn open(
&mut self,
path: &bffs::path::Path,
) -> Result<alloc::boxed::Box<dyn crate::virtual_fs::VirtualNode + '_>, ()> {
if !path.is_empty() {
Err(())
} else {
Ok(Box::new(KeyboardBufferNode::new(self)))
}
}
}
impl IoBase for KeyboardBufferNode<'_> {
type Error = ();
}
impl Read for KeyboardBufferNode<'_> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
let mut buffer = self.buffer.buffer.borrow_mut();
for i in 0..buf.len() {
buf[i] = buffer.pop().unwrap();
}
Ok(buf.len())
}
}
impl Seek for KeyboardBufferNode<'_> {
fn seek(&mut self, pos: io::SeekFrom) -> Result<u64, Self::Error> {
todo!()
}
}
impl Write for KeyboardBufferNode<'_> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
let mut buffer = self.buffer.buffer.borrow_mut();
for input in buf {
buffer.push(*input);
}
Ok(buf.len())
}
fn flush(&mut self) -> Result<(), Self::Error> {
todo!()
}
}
impl VirtualNode for KeyboardBufferNode<'_> {}

67
src/virtual_fs/stdin.rs Normal file
View File

@@ -0,0 +1,67 @@
// use core::cell::RefCell;
// use alloc::boxed::Box;
// use io::{IoBase, Read, Seek, Write};
// use crate::virtual_fs::{VirtualFileSystem, VirtualNode};
// pub const STDIN_BUFFER_SIZE: usize = 4096; // 4Ko
// #[derive(Debug)]
// pub struct Stdin {
// buffer: RefCell<[u8; STDIN_BUFFER_SIZE]>,
// }
// impl Stdin {
// pub fn new() -> Self {
// Self {
// buffer: RefCell::new([0; _]),
// }
// }
// }
// #[derive(Debug)]
// pub struct StdinNode<'a> {
// stdin: &'a Stdin,
// }
// impl VirtualFileSystem for Stdin {
// fn open(
// &mut self,
// path: &bffs::path::Path,
// ) -> Result<alloc::boxed::Box<dyn crate::virtual_fs::VirtualNode + '_>, ()> {
// if !path.is_empty() {
// Err(())
// } else {
// Ok(Box::new(StdinNode { stdin: self }))
// }
// }
// }
// impl IoBase for StdinNode<'_> {
// type Error = ();
// }
// impl Read for StdinNode<'_> {
// fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
// todo!()
// }
// }
// impl Seek for StdinNode<'_> {
// fn seek(&mut self, pos: io::SeekFrom) -> Result<u64, Self::Error> {
// todo!()
// }
// }
// impl Write for StdinNode<'_> {
// fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
// todo!()
// }
// fn flush(&mut self) -> Result<(), Self::Error> {
// todo!()
// }
// }
// impl VirtualNode for StdinNode<'_> {}