diff --git a/crates/bffs/src/path.rs b/crates/bffs/src/path.rs index 524e480..be8edc7 100644 --- a/crates/bffs/src/path.rs +++ b/crates/bffs/src/path.rs @@ -142,3 +142,10 @@ impl From<&str> for PathBuf { } } } + +#[cfg(feature = "alloc")] +impl From for PathBuf { + fn from(val: String) -> Self { + PathBuf { inner: val } + } +} diff --git a/src/data_structures/circular_buffer.rs b/src/data_structures/circular_buffer.rs index 3dc03f8..2bdcb2f 100644 --- a/src/data_structures/circular_buffer.rs +++ b/src/data_structures/circular_buffer.rs @@ -1,6 +1,6 @@ use core::mem::MaybeUninit; -#[derive(Debug)] +#[derive(Debug, Copy)] pub struct CircularBuffer { buffer: [MaybeUninit; SIZE], head: usize, @@ -8,6 +8,12 @@ pub struct CircularBuffer { len: usize, } +impl Clone for CircularBuffer { + fn clone(&self) -> Self { + *self + } +} + impl CircularBuffer { pub const fn new() -> Self { Self { diff --git a/src/interrupt.rs b/src/interrupt.rs index 3d613a1..f80fbb0 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -14,7 +14,7 @@ use crate::{ clear_csr, process::{ExecutionContext, exit_process, sleep}, read_csr, - riscv::disable_interrupt, + riscv::{disable_interrupt, dump_cpu}, scheduler::SCHEDULER, set_csr, syscall, time::{IRQ_M_EXTERNAL, IRQ_M_TIMER, setup_next_timer_interrupt}, @@ -85,7 +85,13 @@ unsafe extern "C" fn machine_trap_handler( ), }; disable_interrupt(); - panic!("{} at PC=0x{:x}, mtval={}", message, mepc, mtval); + panic!( + "{} at PC=0x{:x}, mtval={}\n\n{}", + message, + mepc, + mtval, + dump_cpu() + ); } else { #[allow(clippy::single_match)] match mcause & !(1 << 63) { @@ -120,6 +126,12 @@ unsafe extern "C" fn supervisor_trap_handler( unsafe { (*interrupt_state).mepc = (*interrupt_state).mepc.byte_add(4); } + // Get back to run the syscall again + fn loop_syscall(interrupt_state: *mut ExecutionContext) { + unsafe { + (*interrupt_state).mepc = (*interrupt_state).mepc.byte_sub(4); + } + } // Environment call from S-mode let syscall_u64: u64 = unsafe { (*interrupt_state).a[0] }; @@ -134,10 +146,19 @@ unsafe extern "C" fn supervisor_trap_handler( let mut scheduler = SCHEDULER.lock(); let current_process = scheduler.get_current_process(); - let fd = current_process.next_fd; - current_process.fd_table.insert(fd, virtual_node); - current_process.next_fd += 1; - unsafe { (*interrupt_state).a[0] = fd }; + + let fd = if let Some(fd) = + current_process.fd_table.iter().position(Option::is_none) + { + current_process.fd_table[fd] = Some(virtual_node); + fd + } else { + let fd = current_process.fd_table.len(); + current_process.fd_table.push(Some(virtual_node)); + fd + }; + + unsafe { (*interrupt_state).a[0] = fd as u64 }; } SysCall::Write => { let fd = a1; @@ -146,7 +167,7 @@ unsafe extern "C" fn supervisor_trap_handler( let mut scheduler = SCHEDULER.lock(); let current_process = scheduler.get_current_process(); - let vnode = current_process.fd_table.get_mut(&fd).unwrap(); + let vnode = current_process.fd_table[fd as usize].as_mut().unwrap(); vnode.write(buf).unwrap(); } SysCall::Read => { @@ -156,8 +177,12 @@ unsafe extern "C" fn supervisor_trap_handler( 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(); + let vnode = current_process.fd_table[fd as usize].as_mut().unwrap(); + let res = vnode.read(buf).unwrap(); + if res == 0 && !buf.is_empty() { + loop_syscall(interrupt_state); + scheduler.schedule(&mut interrupt_state); + } } SysCall::Seek => { let fd = a1; @@ -169,7 +194,7 @@ unsafe extern "C" fn supervisor_trap_handler( }; let mut scheduler = SCHEDULER.lock(); let current_process = scheduler.get_current_process(); - let vnode = current_process.fd_table.get_mut(&fd).unwrap(); + let vnode = current_process.fd_table[fd as usize].as_mut().unwrap(); vnode.seek(seek).unwrap(); } SysCall::Alloc => { @@ -360,6 +385,17 @@ unsafe extern "C" fn _supervisor_mode_trap() { csrr t0, sepc sd t0, 248(sp) csrr t0, sstatus + // Move SIE bit to SPIE. Restore_context, in the sret instruction, will do the inverse operation + // Isolate SIE bit (1) + andi t1, t0, 0x2 + // li t1, 0x2 + // Shift to bit 5 (SPIE) + slli t1, t1, 4 + // Clear bit 1 and 5 + li t2, ~0x22 + and t0, t0, t2 + // Add the SPIE bit + or t0, t0, t1 sd t0, 256(sp) mv a0, sp diff --git a/src/keyboard_forwarder.rs b/src/keyboard_forwarder.rs new file mode 100644 index 0000000..e7f176c --- /dev/null +++ b/src/keyboard_forwarder.rs @@ -0,0 +1,70 @@ +use crate::virtio::input::{EventCodeValue, VirtioKeyEvent}; +use crate::{virtual_fs::FILE_SYSTEM, scheduler::SCHEDULER}; + +// Map some common linux input keycodes (evdev) to ASCII +fn keycode_to_ascii(code: u16) -> Option { + match code as u32 { + // letters + 30 => Some('a'), // KEY_A + 48 => Some('b'), // KEY_B + 46 => Some('c'), + 32 => Some('d'), + 18 => Some('e'), + 33 => Some('f'), + 34 => Some('g'), + 35 => Some('h'), + 23 => Some('i'), + 36 => Some('j'), + 37 => Some('k'), + 38 => Some('l'), + 50 => Some('m'), + 49 => Some('n'), + 24 => Some('o'), + 25 => Some('p'), + 16 => Some('q'), + 19 => Some('r'), + 31 => Some('s'), + 20 => Some('t'), + 22 => Some('u'), + 47 => Some('v'), + 17 => Some('w'), + 45 => Some('x'), + 21 => Some('y'), + 44 => Some('z'), + // digits + 2 => Some('1'), + 3 => Some('2'), + 4 => Some('3'), + 5 => Some('4'), + 6 => Some('5'), + 7 => Some('6'), + 8 => Some('7'), + 9 => Some('8'), + 10 => Some('9'), + 11 => Some('0'), + // space, enter, backspace + 57 => Some(' '), + 28 => Some('\n'), + 14 => Some('\x08'), + _ => None, + } +} + +pub fn keyboard_forwarder() { + // Open keyboard device and stdin device + let mut kbd = unsafe { FILE_SYSTEM.open("/dev/input/keyboard".as_ref()).unwrap() }; + let mut stdin = unsafe { FILE_SYSTEM.open("/dev/stdin".as_ref()).unwrap() }; + + let mut buf = [0u8; core::mem::size_of::()]; + loop { + // Read full virtio key event + if let Ok(_) = kbd.read(&mut buf) { + let ev = unsafe { &*(buf.as_ptr() as *const VirtioKeyEvent) }; + if ev.value == EventCodeValue::Pressed { + if let Some(c) = keycode_to_ascii(ev.code) { + let _ = stdin.write(&[c as u8]); + } + } + } + } +} diff --git a/src/keymap.rs b/src/keymap.rs new file mode 100644 index 0000000..b750b75 --- /dev/null +++ b/src/keymap.rs @@ -0,0 +1,64 @@ +pub enum KeyType { + Ascii(char), + // Special, // F1, Home, etc. + Modifier, // Shift, Ctrl + Unknown, +} + +pub const fn map_keycode(code: u16, shift: bool) -> KeyType { + match code { + // Numbers row + 2..=11 => { + let val = if shift { + [')', '!', '@', '#', '$', '%', '^', '&', '*', '('][(code - 2) as usize] + } else { + (code as u8 - 2 + b'1') as char + }; + if code == 11 && !shift { + KeyType::Ascii('0') + } else { + KeyType::Ascii(val) + } + } + + // Letters (Simplified QWERTY) + 16 => KeyType::Ascii(if shift { 'Q' } else { 'q' }), + 17 => KeyType::Ascii(if shift { 'W' } else { 'w' }), + 18 => KeyType::Ascii(if shift { 'E' } else { 'e' }), + 19 => KeyType::Ascii(if shift { 'R' } else { 'r' }), + 20 => KeyType::Ascii(if shift { 'T' } else { 't' }), + 21 => KeyType::Ascii(if shift { 'Y' } else { 'y' }), + 22 => KeyType::Ascii(if shift { 'U' } else { 'u' }), + 23 => KeyType::Ascii(if shift { 'I' } else { 'i' }), + 24 => KeyType::Ascii(if shift { 'O' } else { 'o' }), + 25 => KeyType::Ascii(if shift { 'P' } else { 'p' }), + 30 => KeyType::Ascii(if shift { 'A' } else { 'a' }), + 31 => KeyType::Ascii(if shift { 'S' } else { 's' }), + 32 => KeyType::Ascii(if shift { 'D' } else { 'd' }), + 33 => KeyType::Ascii(if shift { 'F' } else { 'f' }), + 34 => KeyType::Ascii(if shift { 'G' } else { 'g' }), + 35 => KeyType::Ascii(if shift { 'H' } else { 'h' }), + 36 => KeyType::Ascii(if shift { 'J' } else { 'j' }), + 37 => KeyType::Ascii(if shift { 'K' } else { 'k' }), + 38 => KeyType::Ascii(if shift { 'L' } else { 'l' }), + 44 => KeyType::Ascii(if shift { 'Z' } else { 'z' }), + 45 => KeyType::Ascii(if shift { 'X' } else { 'x' }), + 46 => KeyType::Ascii(if shift { 'C' } else { 'c' }), + 47 => KeyType::Ascii(if shift { 'V' } else { 'v' }), + 48 => KeyType::Ascii(if shift { 'B' } else { 'b' }), + 49 => KeyType::Ascii(if shift { 'N' } else { 'n' }), + 50 => KeyType::Ascii(if shift { 'M' } else { 'm' }), + + // Control + 28 => KeyType::Ascii('\n'), + 57 => KeyType::Ascii(' '), + 14 => KeyType::Ascii('\x08'), // Backspace + 1 => KeyType::Ascii('\x1b'), // Escape + + // Modifiers + 42 | 54 => KeyType::Modifier, // LShift, RShift + 29 | 97 => KeyType::Modifier, // LCtrl, RCtrl + + _ => KeyType::Unknown, + } +} diff --git a/src/main.rs b/src/main.rs index ebdcd91..a72cbf5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,14 +21,16 @@ use log::info; use crate::{ cursor::{clear_cursor, draw_cursor}, io::init_log, + keymap::map_keycode, pci::{PciDeviceIterator, scan_virtio_devices}, riscv::enable_supervisor_interrupt, scheduler::{SCHEDULER, idle}, + tty::TTY0, user::{proc2, test}, vga::Vga, virtio::{ Virtqueue, - input::{EventCodeValue, VirtioPciDriver, init_plic_pci}, + input::{EventCodeValue, VirtioInputEvent, VirtioPciDriver, init_plic_pci}, }, virtual_fs::{FILE_SYSTEM, VirtualFileSystem, init_file_system}, }; @@ -42,6 +44,7 @@ mod draw; mod fs; mod interrupt; mod io; +mod keymap; mod panic_handler; mod pci; mod process; @@ -69,17 +72,50 @@ const _: () = assert!(core::mem::size_of::() == core::mem::size_of:: #[cfg(not(target_endian = "little"))] compile_error! {"This kernel implementation assume endianness is little-endian. Some memory access like PCI could not work in big-endian."} -// 1. Allouer de la mémoire statique alignée pour la queue +#[derive(Debug, Clone, Copy, Default)] +pub struct KeyboardState { + // ctrl_modifier: bool, + maj_modifier: bool, +} + +impl KeyboardState { + pub const fn new() -> Self { + Self { + // ctrl_modifier: false, + maj_modifier: false, + } + } +} + +static mut KBD_STATE: KeyboardState = KeyboardState::new(); 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(); + kbd_buffer + .write(core::mem::transmute::< + &VirtioInputEvent, + &[u8; size_of::()], + >(event)) + .unwrap(); + if event.is_key() { let event = event.as_key_event(); if event.value == EventCodeValue::Pressed { - println!("event: {:#?}", event); - kbd_buffer.write(&[event.code as u8]).unwrap(); + #[allow(clippy::single_match)] + match map_keycode(event.code, KBD_STATE.maj_modifier) { + keymap::KeyType::Ascii(c) => { + let mut buf = [0; 4]; + let to_send = c.encode_utf8(&mut buf); + for c in to_send.as_bytes() { + println!("key: {}", c); + TTY0.buffer.borrow_mut().push(*c); + } + } + _ => {} + } + // println!("event: {:#?}", event); } } else { // println!("key pressed, {:#?}", event); @@ -135,12 +171,12 @@ pub extern "C" fn supervisor_mode_entry() { info!("Hello World !"); // unsafe { Vga.draw_string(10, 10, "Hello World !", Color::WHITE, Color::BLACK) }; - SCHEDULER.lock().create_process(Box::new(test), "proc1"); - SCHEDULER.lock().create_process(Box::new(proc2), "proc2"); + // SCHEDULER.lock().create_process(Box::new(test), "proc1"); + // SCHEDULER.lock().create_process(Box::new(proc2), "proc2"); - SCHEDULER - .lock() - .create_process_from_file("/usr/bin/test_pic"); + // SCHEDULER + // .lock() + // .create_process_from_file("/usr/bin/test_pic"); enable_supervisor_interrupt(); diff --git a/src/process.rs b/src/process.rs index beefbc2..4066c64 100644 --- a/src/process.rs +++ b/src/process.rs @@ -12,19 +12,22 @@ use core::time::Duration; use alloc::{boxed::Box, format, string::String, vec::Vec}; use bffs::path::Path; use goblin::elf::reloc::R_RISCV_RELATIVE; -use hashbrown::HashMap; use shared::syscall::exit; use crate::{ println, - scheduler::{SCHEDULER, Scheduler}, + scheduler::{ACTIVE_PID, SCHEDULER, Scheduler}, time::elapsed_time_since_startup, + tty::TTY0, virtual_fs::{FILE_SYSTEM, VirtualFileSystem, VirtualNode}, }; /// Size of the stack allocated to each process (in 64-bit words). const STACK_SIZE: usize = 4096; +/// MSTATUS bit to enable supervisor mode interrupts. +const MSTATUS_SIE: u64 = 1 << 1; + /// MSTATUS bit to enable supervisor mode interrupts. const MSTATUS_SPIE: u64 = 1 << 5; @@ -91,9 +94,7 @@ pub struct Process { /// Process stack. pub stack: [u64; STACK_SIZE], /// File descriptor table. - pub fd_table: HashMap>, - /// Next available file descriptor. - pub next_fd: u64, + pub fd_table: Vec>>, } unsafe impl Send for Process {} @@ -118,8 +119,7 @@ impl Default for Process { }, stack: [0; _], entry: None, - fd_table: HashMap::new(), - next_fd: 0, + fd_table: Vec::new(), } } } @@ -297,10 +297,17 @@ 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()); + process.fd_table = Vec::new(); + FILE_SYSTEM.mount( + format!("/proc/{}/0", process.pid).into(), + Box::new(TTY0.clone()), + ); + // FD 0 + process.fd_table.push(Some( + FILE_SYSTEM + .open(format!("/proc/{}/0", process.pid).as_ref()) + .unwrap(), + )); // Configure execution context // a0 contains the pointer to the function to execute @@ -368,7 +375,7 @@ extern "C" fn process_launcher(code: *const Box) { pub fn exit_process(interrupt_context: &mut *mut ExecutionContext) { // SAFETY: ACTIVE_PID is maintained by the scheduler and is always valid. let mut scheduler = SCHEDULER.lock(); - let active_pid = scheduler.active_pid; + let active_pid = ACTIVE_PID.load(core::sync::atomic::Ordering::Relaxed); scheduler.process_table.remove(&active_pid).unwrap(); // Transfer control to the scheduler (does not return) scheduler.schedule(interrupt_context) diff --git a/src/riscv.rs b/src/riscv.rs index 50f5406..4e36463 100644 --- a/src/riscv.rs +++ b/src/riscv.rs @@ -6,6 +6,10 @@ use core::arch::naked_asm; +use alloc::fmt::format; +use alloc::format; +use alloc::string::String; + use crate::clear_csr; use crate::read_csr; use crate::set_csr; @@ -115,3 +119,22 @@ pub extern "C" fn exit_qemu() -> ! { " ) } + +pub fn dump_cpu() -> String { + let mstatus: u64 = read_csr!(mstatus); + let mepc: u64 = read_csr!(mepc); + let sstatus: u64 = read_csr!(sstatus); + let sepc: u64 = read_csr!(sepc); + let stval: u64 = read_csr!(stval); + + format!( + "-------- CPU DUMP -------- +mstatus: {:#016x} +mepc: {:#016x} +sstatus: {:#016x} +sepc: {:#016x} +stval: {:#016x} +--------------------------", + mstatus, mepc, sstatus, sepc, stval + ) +} diff --git a/src/scheduler.rs b/src/scheduler.rs index 82cbbe6..9c9c6cc 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -3,7 +3,7 @@ //! //! This module exposes the global process table, the scheduler initialization //! and a simple round-robin scheduler used by the kernel. -use core::{arch::riscv64::wfi, cell::LazyCell, ops::Bound}; +use core::{arch::riscv64::wfi, cell::LazyCell, ops::Bound, sync::atomic::AtomicU64}; use alloc::{boxed::Box, collections::BTreeMap}; use log::info; @@ -17,13 +17,13 @@ use crate::{ #[derive(Debug)] pub struct Scheduler { pub next_pid: u64, - pub active_pid: u64, pub process_table: BTreeMap>, } +pub static ACTIVE_PID: AtomicU64 = AtomicU64::new(0); + pub static SCHEDULER: Mutex> = Mutex::new(LazyCell::new(|| Scheduler { next_pid: 0, - active_pid: 0, process_table: BTreeMap::new(), })); @@ -60,7 +60,7 @@ impl Scheduler { pub fn schedule(&mut self, interrupt_state: &mut *mut ExecutionContext) { // info!("scheduler"); unsafe { - let prev_pid = self.active_pid; + let prev_pid = ACTIVE_PID.load(core::sync::atomic::Ordering::Relaxed); if let Some(previous_process) = self.process_table.get_mut(&prev_pid) { previous_process.ctx = **interrupt_state; @@ -73,27 +73,31 @@ impl Scheduler { .process_table .range_mut((Bound::Excluded(prev_pid), Bound::Unbounded)); - self.active_pid = loop { - if let Some((pid, current_process)) = current_process_iter.next() { - if current_process.state == ProcessState::Asleep - && time::elapsed_time_since_startup() > current_process.wake_time - { - current_process.state = ProcessState::Activable; + ACTIVE_PID.store( + loop { + if let Some((pid, current_process)) = current_process_iter.next() { + if current_process.state == ProcessState::Asleep + && time::elapsed_time_since_startup() > current_process.wake_time + { + current_process.state = ProcessState::Activable; + } + if current_process.state == ProcessState::Activable { + current_process.state = ProcessState::Active; + *interrupt_state = &raw mut current_process.ctx; + break *pid; + }; + } else { + current_process_iter = self + .process_table + .range_mut((Bound::Unbounded, Bound::Included(prev_pid))) } - if current_process.state == ProcessState::Activable { - current_process.state = ProcessState::Active; - *interrupt_state = &raw mut current_process.ctx; - break *pid; - }; - } else { - current_process_iter = self - .process_table - .range_mut((Bound::Unbounded, Bound::Included(prev_pid))) - } - }; + }, + core::sync::atomic::Ordering::Relaxed, + ); } } pub fn get_current_process(&mut self) -> &mut Process { - self.process_table.get_mut(&self.active_pid).unwrap() + let active_pid = ACTIVE_PID.load(core::sync::atomic::Ordering::Relaxed); + self.process_table.get_mut(&active_pid).unwrap() } } diff --git a/src/time.rs b/src/time.rs index be0bb77..eade1e7 100644 --- a/src/time.rs +++ b/src/time.rs @@ -26,7 +26,7 @@ const CLINT_TIMER: *const u64 = 0x0200_bff8 as *const u64; /// The hardware timer frequency (Hz). const TIMER_FREQUENCY: u64 = 10_000_000; // 10 MHz /// The frequency at which timer interrupts should occur (Hz). -const INTERRUPT_FREQUENCY: u64 = 20; // 20 Hz +const INTERRUPT_FREQUENCY: u64 = 200; // 20 Hz /// Stores the instant when the kernel started. static START_TIME: AtomicU64 = AtomicU64::new(0); diff --git a/src/tty.rs b/src/tty.rs index d56fdef..b00426e 100644 --- a/src/tty.rs +++ b/src/tty.rs @@ -1,29 +1,35 @@ -use core::cell::RefCell; +use core::cell::{LazyCell, RefCell}; use alloc::{boxed::Box, rc::Rc}; use io::{IoBase, Read, Seek, Write}; use crate::{ + data_structures::circular_buffer::CircularBuffer, virtual_console::VirtualConsole, virtual_fs::{VirtualFileSystem, VirtualNode}, }; -#[derive(Debug)] +pub const TTY_BUFFER_SIZE: usize = 4096; // 4Ko +pub static mut TTY0: LazyCell = LazyCell::new(Tty::new); + +#[derive(Debug, Clone)] pub struct Tty { + pub buffer: Rc>>, console: Rc>, } impl Tty { pub fn new() -> Self { Self { + buffer: RefCell::new(CircularBuffer::new()).into(), console: RefCell::new(VirtualConsole::new()).into(), } } } #[derive(Debug)] -struct TtyNode { - console: Rc>, +struct TtyNode<'a> { + tty: &'a Tty, } impl VirtualFileSystem for Tty { @@ -34,32 +40,36 @@ impl VirtualFileSystem for Tty { if !path.is_empty() { Err(()) } else { - Ok(Box::new(TtyNode { - console: self.console.clone(), - })) + Ok(Box::new(TtyNode { tty: self })) } } } -impl IoBase for TtyNode { +impl IoBase for TtyNode<'_> { type Error = (); } -impl Read for TtyNode { - fn read(&mut self, _buf: &mut [u8]) -> Result { - unimplemented!() +impl Read for TtyNode<'_> { + fn read(&mut self, buf: &mut [u8]) -> Result { + let mut buffer = self.tty.buffer.borrow_mut(); + let max_len = buffer.len(); + (0..buf.len().min(max_len)).for_each(|i| { + buf[i] = buffer.pop().unwrap(); + }); + Ok(buf.len().min(max_len)) } } -impl Seek for TtyNode { +impl Seek for TtyNode<'_> { fn seek(&mut self, _pos: io::SeekFrom) -> Result { unimplemented!() } } -impl Write for TtyNode { +impl Write for TtyNode<'_> { fn write(&mut self, buf: &[u8]) -> Result { - self.console + self.tty + .console .borrow_mut() .write_str(str::from_utf8(buf).unwrap()); Ok(buf.len()) @@ -70,4 +80,4 @@ impl Write for TtyNode { } } -impl VirtualNode for TtyNode {} +impl VirtualNode for TtyNode<'_> {} diff --git a/src/virtual_fs.rs b/src/virtual_fs.rs index 06314c6..b026e8f 100644 --- a/src/virtual_fs.rs +++ b/src/virtual_fs.rs @@ -10,8 +10,14 @@ use io::{IoBase, Read, Seek, Write}; pub mod keyboard; pub mod stdin; +pub mod virtual_stdin; -use crate::{fs::Disk, tty::Tty, vga::Vga, virtual_fs::keyboard::KeyboardBuffer}; +use crate::{ + fs::Disk, + tty::TTY0, + vga::Vga, + virtual_fs::{keyboard::KeyboardBuffer, virtual_stdin::VirtualStdin}, +}; pub trait VirtualNode: IoBase + Read + Write + Seek + Debug {} @@ -55,12 +61,12 @@ pub static mut FILE_SYSTEM: LazyCell = LazyCell::new(|| MainFile 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/tty0".into(), Box::new(TTY0.clone())); FILE_SYSTEM.mount( "/dev/input/keyboard".into(), Box::new(KeyboardBuffer::new()), ); - // FILE_SYSTEM.mount("/dev/stdin".into(), Box::new(Stdin::new())); + FILE_SYSTEM.mount("/dev/stdin".into(), Box::new(VirtualStdin::new())); } } diff --git a/src/virtual_fs/keyboard.rs b/src/virtual_fs/keyboard.rs index 9960396..a3846af 100644 --- a/src/virtual_fs/keyboard.rs +++ b/src/virtual_fs/keyboard.rs @@ -5,7 +5,6 @@ use io::{IoBase, Read, Seek, Write}; use crate::{ data_structures::circular_buffer::CircularBuffer, - println, virtual_fs::{VirtualFileSystem, VirtualNode}, }; @@ -55,15 +54,15 @@ impl IoBase for KeyboardBufferNode<'_> { impl Read for KeyboardBufferNode<'_> { fn read(&mut self, buf: &mut [u8]) -> Result { let mut buffer = self.buffer.buffer.borrow_mut(); - for i in 0..buf.len() { + (0..buf.len()).for_each(|i| { buf[i] = buffer.pop().unwrap(); - } + }); Ok(buf.len()) } } impl Seek for KeyboardBufferNode<'_> { - fn seek(&mut self, pos: io::SeekFrom) -> Result { + fn seek(&mut self, _pos: io::SeekFrom) -> Result { todo!() } } diff --git a/src/virtual_fs/stdin.rs b/src/virtual_fs/stdin.rs index 28255da..2c3fb2d 100644 --- a/src/virtual_fs/stdin.rs +++ b/src/virtual_fs/stdin.rs @@ -3,19 +3,22 @@ // use alloc::boxed::Box; // use io::{IoBase, Read, Seek, Write}; -// use crate::virtual_fs::{VirtualFileSystem, VirtualNode}; +// use crate::{ +// data_structures::circular_buffer::CircularBuffer, +// virtual_fs::{VirtualFileSystem, VirtualNode}, +// }; // pub const STDIN_BUFFER_SIZE: usize = 4096; // 4Ko // #[derive(Debug)] // pub struct Stdin { -// buffer: RefCell<[u8; STDIN_BUFFER_SIZE]>, +// buffer: RefCell>, // } // impl Stdin { // pub fn new() -> Self { // Self { -// buffer: RefCell::new([0; _]), +// buffer: RefCell::new(CircularBuffer::new()), // } // } // } @@ -44,7 +47,11 @@ // impl Read for StdinNode<'_> { // fn read(&mut self, buf: &mut [u8]) -> Result { -// todo!() +// let mut buffer = self.stdin.buffer.borrow_mut(); +// for i in 0..buf.len() { +// buf[i] = buffer.pop().unwrap(); +// } +// Ok(buf.len()) // } // } diff --git a/src/virtual_fs/symbolic_link.rs b/src/virtual_fs/symbolic_link.rs new file mode 100644 index 0000000..08144fd --- /dev/null +++ b/src/virtual_fs/symbolic_link.rs @@ -0,0 +1 @@ +pub struct SymbolicLink {} diff --git a/src/virtual_fs/virtual_stdin.rs b/src/virtual_fs/virtual_stdin.rs new file mode 100644 index 0000000..28e25a9 --- /dev/null +++ b/src/virtual_fs/virtual_stdin.rs @@ -0,0 +1,84 @@ +use alloc::{boxed::Box, format}; +use io::{IoBase, Read, Seek, Write}; + +use crate::{ + scheduler::ACTIVE_PID, + virtual_fs::{FILE_SYSTEM, VirtualFileSystem, VirtualNode}, +}; + +#[derive(Debug)] +pub struct VirtualStdin {} + +#[derive(Debug)] +pub struct VirtualStdinNode {} + +impl VirtualStdin { + pub fn new() -> Self { + Self {} + } +} + +impl VirtualFileSystem for VirtualStdin { + fn open( + &mut self, + path: &bffs::path::Path, + ) -> Result, ()> { + if !path.is_empty() { + Err(()) + } else { + Ok(Box::new(VirtualStdinNode {})) + } + } +} + +impl IoBase for VirtualStdinNode { + type Error = (); +} + +impl Read for VirtualStdinNode { + fn read(&mut self, buf: &mut [u8]) -> Result { + let pid = ACTIVE_PID.load(core::sync::atomic::Ordering::Relaxed); + unsafe { + FILE_SYSTEM + .open(format!("/proc/{pid}/0").as_ref()) + .unwrap() + .read(buf) + } + } +} + +impl Seek for VirtualStdinNode { + fn seek(&mut self, pos: io::SeekFrom) -> Result { + let pid = ACTIVE_PID.load(core::sync::atomic::Ordering::Relaxed); + unsafe { + FILE_SYSTEM + .open(format!("/proc/{pid}/0").as_ref()) + .unwrap() + .seek(pos) + } + } +} + +impl Write for VirtualStdinNode { + fn write(&mut self, buf: &[u8]) -> Result { + let pid = ACTIVE_PID.load(core::sync::atomic::Ordering::Relaxed); + unsafe { + FILE_SYSTEM + .open(format!("/proc/{pid}/0").as_ref()) + .unwrap() + .write(buf) + } + } + + fn flush(&mut self) -> Result<(), Self::Error> { + let pid = ACTIVE_PID.load(core::sync::atomic::Ordering::Relaxed); + unsafe { + FILE_SYSTEM + .open(format!("/proc/{pid}/0").as_ref()) + .unwrap() + .flush() + } + } +} + +impl VirtualNode for VirtualStdinNode {} diff --git a/user/test_pic/src/main.rs b/user/test_pic/src/main.rs index 0cefb27..eaad6c9 100644 --- a/user/test_pic/src/main.rs +++ b/user/test_pic/src/main.rs @@ -12,13 +12,19 @@ fn main() { // syscall::seek(&mut file, SeekFrom::End(-3)); // syscall::write(&mut file, &[255; 6400 * 50]); syscall::sleep(Duration::from_secs_f64(2.0)); - let mut stdin = syscall::open("/dev/input/keyboard"); - let mut test = [0; 2]; - syscall::read(&mut stdin, &mut test); + let mut stdin = syscall::open("/dev/tty0"); let mut file = syscall::open("/dev/tty0"); - syscall::write(&mut file, b"Hi !\nnice tty\x08"); - println!( - "Hello from PIC program loaded dynamically with custom std and a better justfile, and syscalls ! {:?}", - test - ); + loop { + let mut test = [0; 2]; + syscall::read(&mut stdin, &mut test); + let len = *test.iter().find(|x| **x == 0).unwrap_or(&1) + 1; + syscall::write( + &mut file, + str::from_utf8(&test[..len as usize]).unwrap().as_bytes(), + ); + } + // println!( + // "Hello from PIC program loaded dynamically with custom std and a better justfile, and syscalls ! {:?}", + // str::from_utf8(&test) + // ); }