From 20e3152e1eea97f87d644c3023391e172bc83c93 Mon Sep 17 00:00:00 2001 From: login Date: Fri, 31 Mar 2023 12:54:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86TTY=E4=B8=8Estdio=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5,=E5=AE=9E=E7=8E=B0=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E7=9A=84stdio=E5=8A=9F=E8=83=BD=20(#217)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 将stdio与tty接上 --- kernel/src/driver/keyboard/ps2_keyboard.c | 10 +- kernel/src/driver/keyboard/ps2_keyboard.rs | 10 +- kernel/src/driver/tty/mod.rs | 7 +- kernel/src/driver/tty/tty_device.rs | 214 +++++++++++++++++++-- kernel/src/filesystem/devfs/mod.rs | 35 +++- kernel/src/filesystem/vfs/file.rs | 14 +- kernel/src/filesystem/vfs/mod.rs | 32 ++- kernel/src/filesystem/vfs/mount.rs | 4 +- kernel/src/include/bindings/wrapper.h | 11 +- kernel/src/lib.rs | 2 - kernel/src/libs/keyboard_parser.rs | 99 ++++++---- kernel/src/main.c | 5 +- kernel/src/process/process.c | 12 +- kernel/src/process/process.rs | 35 +++- kernel/src/syscall/mod.rs | 2 +- kernel/src/time/mod.rs | 9 + user/apps/shell/cmd.c | 10 + user/apps/shell/shell.c | 93 +++++---- user/libs/libc/src/include/export/stdio.h | 2 +- user/libs/libc/src/printf.c | 70 +++---- user/libs/libc/src/stdio.c | 21 +- 21 files changed, 528 insertions(+), 169 deletions(-) diff --git a/kernel/src/driver/keyboard/ps2_keyboard.c b/kernel/src/driver/keyboard/ps2_keyboard.c index 593e2d58..2ef4db72 100644 --- a/kernel/src/driver/keyboard/ps2_keyboard.c +++ b/kernel/src/driver/keyboard/ps2_keyboard.c @@ -146,11 +146,11 @@ void ps2_keyboard_handler(ul irq_num, ul buf_vaddr, struct pt_regs *regs) unsigned char x = io_in8(PORT_PS2_KEYBOARD_DATA); ps2_keyboard_parse_keycode((uint8_t)x); uint8_t count = kfifo_in((struct kfifo_t *)buf_vaddr, &x, sizeof(unsigned char)); - if (count == 0) - { - kwarn("ps2 keyboard buffer full."); - return; - } + // if (count == 0) + // { + // kwarn("ps2 keyboard buffer full."); + // return; + // } wait_queue_wakeup(&ps2_keyboard_wait_queue, PROC_UNINTERRUPTIBLE); diff --git a/kernel/src/driver/keyboard/ps2_keyboard.rs b/kernel/src/driver/keyboard/ps2_keyboard.rs index bb799f7b..2a3505f9 100644 --- a/kernel/src/driver/keyboard/ps2_keyboard.rs +++ b/kernel/src/driver/keyboard/ps2_keyboard.rs @@ -3,6 +3,7 @@ use core::sync::atomic::AtomicI32; use alloc::sync::{Arc, Weak}; use crate::{ + driver::tty::tty_device::TTY_DEVICES, filesystem::{ devfs::{devfs_register, DevFS, DeviceINode}, vfs::{core::generate_inode_id, file::FileMode, FileType, IndexNode, Metadata, PollStatus}, @@ -17,7 +18,14 @@ use crate::{ pub struct LockedPS2KeyBoardInode(RwLock, AtomicI32); // self.1 用来记录有多少个文件打开了这个inode lazy_static! { - static ref PS2_KEYBOARD_FSM: SpinLock = SpinLock::new(TypeOneFSM::new()); + static ref PS2_KEYBOARD_FSM: SpinLock = { + let tty0 = TTY_DEVICES + .read() + .get("tty0") + .expect("Initializing PS2_KEYBOARD_FSM: Cannot found TTY0!") + .clone(); + SpinLock::new(TypeOneFSM::new(tty0)) + }; } #[derive(Debug)] diff --git a/kernel/src/driver/tty/mod.rs b/kernel/src/driver/tty/mod.rs index f4d9b162..2408e657 100644 --- a/kernel/src/driver/tty/mod.rs +++ b/kernel/src/driver/tty/mod.rs @@ -5,7 +5,7 @@ use thingbuf::mpsc::{ errors::{TryRecvError, TrySendError}, }; -use crate::libs::rwlock::RwLock; +use crate::{libs::rwlock::RwLock, kdebug}; pub mod tty_device; @@ -59,6 +59,7 @@ struct TtyCore { } #[derive(Debug)] +#[allow(dead_code)] pub enum TtyError { /// 缓冲区满,返回成功传送的字节数 BufferFull(usize), @@ -281,16 +282,18 @@ impl TtyCore { /// @brief 关闭输入回显 #[inline] + #[allow(dead_code)] pub fn disable_echo(&self) { self.state.write().set(TtyCoreState::ECHO_ON, false); } - + /// @brief 判断当前tty核心,是否开启了输入回显 /// /// @return true 开启了输入回显 /// /// @return false 未开启输入回显 #[inline] + #[allow(dead_code)] pub fn echo_enabled(&self) -> bool { return self.state.read().contains(TtyCoreState::ECHO_ON); } diff --git a/kernel/src/driver/tty/tty_device.rs b/kernel/src/driver/tty/tty_device.rs index 8eb84758..fe4d889c 100644 --- a/kernel/src/driver/tty/tty_device.rs +++ b/kernel/src/driver/tty/tty_device.rs @@ -1,31 +1,62 @@ -use alloc::sync::{Arc, Weak}; +use alloc::{ + collections::BTreeMap, + string::{String, ToString}, + sync::{Arc, Weak}, +}; use crate::{ filesystem::{ - devfs::{DeviceINode, DevFS}, - vfs::{file::FileMode, FilePrivateData, IndexNode}, + devfs::{devfs_register, DevFS, DeviceINode}, + vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, Metadata, ROOT_INODE}, }, - kerror, libs::rwlock::RwLock, syscall::SystemError, + include::bindings::bindings::{printk_color, textui_putchar, BLACK, WHITE}, + kdebug, kerror, + libs::rwlock::RwLock, + print, + syscall::SystemError, }; use super::{TtyCore, TtyError, TtyFileFlag, TtyFilePrivateData}; +lazy_static! { + /// 所有TTY设备的B树。用于根据名字,找到Arc + /// TODO: 待设备驱动模型完善,具有类似功能的机制后,删掉这里 + pub static ref TTY_DEVICES: RwLock>> = RwLock::new(BTreeMap::new()); +} + +/// @brief TTY设备 #[derive(Debug)] pub struct TtyDevice { + /// TTY核心 core: TtyCore, - fs: RwLock> - + /// TTY所属的文件系统 + fs: RwLock>, + /// TTY设备私有信息 + private_data: RwLock, +} + +#[derive(Debug)] +struct TtyDevicePrivateData { + /// TTY设备名(如tty1) + name: String, + /// TTY设备文件的元数据 + metadata: Metadata, + // TODO: 增加指向输出端口连接的设备的指针 } impl TtyDevice { - pub fn new() -> Arc { - return Arc::new(TtyDevice { + pub fn new(name: &str) -> Arc { + let result = Arc::new(TtyDevice { core: TtyCore::new(), fs: RwLock::new(Weak::default()), + private_data: TtyDevicePrivateData::new(name), }); + // 默认开启输入回显 + result.core.enable_echo(); + return result; } - /// @brief 判断文件私有信息是否为TTY的私有信息 + /// @brief 判断文件私有信息是否为TTY文件的私有信息 #[inline] fn verify_file_private_data<'a>( &self, @@ -36,6 +67,39 @@ impl TtyDevice { } return Err(SystemError::EIO); } + + /// @brief 获取TTY设备名 + #[inline] + pub fn name(&self) -> String { + return self.private_data.read().name.clone(); + } + + /// @brief 检查TTY文件的读写参数是否合法 + #[inline] + pub fn check_rw_param(&self, len: usize, buf: &[u8]) -> Result<(), SystemError> { + if len > buf.len() { + return Err(SystemError::EINVAL); + } + return Ok(()); + } + + /// @brief 向TTY的输入端口导入数据 + pub fn input(&self, buf: &[u8]) -> Result { + let r: Result = self.core.input(buf, false); + if r.is_ok() { + return Ok(r.unwrap()); + } + + let r = r.unwrap_err(); + match r { + TtyError::BufferFull(x) => return Ok(x), + TtyError::Closed => return Err(SystemError::ENODEV), + e => { + kerror!("tty error occurred while writing data to its input port, msg={e:?}"); + return Err(SystemError::EBUSY); + } + } + } } impl DeviceINode for TtyDevice { @@ -45,15 +109,40 @@ impl DeviceINode for TtyDevice { } impl IndexNode for TtyDevice { + /// @brief 打开TTY设备 + /// + /// @param data 文件私有信息 + /// @param mode 打开模式 + /// + /// TTY设备通过mode来确定这个文件到底是stdin/stdout/stderr + /// - mode的值为O_RDONLY时,表示这个文件是stdin + /// - mode的值为O_WRONLY时,表示这个文件是stdout + /// - mode的值为O_WRONLY | O_SYNC时,表示这个文件是stderr fn open(&self, data: &mut FilePrivateData, mode: &FileMode) -> Result<(), SystemError> { - let p = TtyFilePrivateData::default(); + let mut p = TtyFilePrivateData::default(); + + // 检查打开模式 + let accmode = mode.accmode(); + if accmode == FileMode::O_RDONLY.accmode() { + p.flags.insert(TtyFileFlag::STDIN); + } else if accmode == FileMode::O_WRONLY.accmode() { + if mode.contains(FileMode::O_SYNC) { + p.flags.insert(TtyFileFlag::STDERR); + } else { + p.flags.insert(TtyFileFlag::STDOUT); + } + } else { + return Err(SystemError::EINVAL); + } + + // 保存文件私有信息 *data = FilePrivateData::Tty(p); return Ok(()); } fn read_at( &self, - offset: usize, + _offset: usize, len: usize, buf: &mut [u8], data: &mut crate::filesystem::vfs::FilePrivateData, @@ -65,9 +154,10 @@ impl IndexNode for TtyDevice { return Err(e); } }; + self.check_rw_param(len, buf)?; // 读取stdin队列 - let r: Result = self.core.read_stdin(buf, true); + let r: Result = self.core.read_stdin(&mut buf[0..len], true); if r.is_ok() { return Ok(r.unwrap()); } @@ -76,6 +166,7 @@ impl IndexNode for TtyDevice { TtyError::EOF(n) => { return Ok(n); } + x => { kerror!("Error occurred when reading tty, msg={x:?}"); return Err(SystemError::ECONNABORTED); @@ -85,7 +176,7 @@ impl IndexNode for TtyDevice { fn write_at( &self, - offset: usize, + _offset: usize, len: usize, buf: &[u8], data: &mut crate::filesystem::vfs::FilePrivateData, @@ -98,16 +189,19 @@ impl IndexNode for TtyDevice { } }; + self.check_rw_param(len, buf)?; + // 根据当前文件是stdout还是stderr,选择不同的发送方式 let r: Result = if data.flags.contains(TtyFileFlag::STDOUT) { - self.core.stdout(buf, true) + self.core.stdout(&buf[0..len], true) } else if data.flags.contains(TtyFileFlag::STDERR) { - self.core.stderr(buf, true) + self.core.stderr(&buf[0..len], true) } else { return Err(SystemError::EPERM); }; if r.is_ok() { + self.sync().expect("Failed to sync tty device!"); return Ok(r.unwrap()); } @@ -131,4 +225,94 @@ impl IndexNode for TtyDevice { fn list(&self) -> Result, SystemError> { return Err(SystemError::ENOTSUP); } + + fn metadata(&self) -> Result { + return Ok(self.private_data.read().metadata.clone()); + } + + fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> { + return Ok(()); + } + + fn sync(&self) -> Result<(), SystemError> { + // TODO: 引入IO重定向后,需要将输出重定向到对应的设备。 + // 目前只是简单的输出到屏幕(为了实现的简便) + + loop { + let mut buf = [0u8; 512]; + let r: Result = self.core.read_output(&mut buf[0..511], false); + let len; + match r { + Ok(x) => { + len = x; + } + Err(TtyError::EOF(x)) | Err(TtyError::BufferEmpty(x)) => { + len = x; + } + _ => return Err(SystemError::EIO), + } + + if len == 0 { + break; + } + // 输出到屏幕 + print!("{}", unsafe { + core::str::from_utf8_unchecked(&buf[0..len]) + }); + } + return Ok(()); + } +} + +impl TtyDevicePrivateData { + pub fn new(name: &str) -> RwLock { + let mut metadata = Metadata::new(FileType::CharDevice, 0o755); + metadata.size = TtyCore::STDIN_BUF_SIZE as i64; + return RwLock::new(TtyDevicePrivateData { + name: name.to_string(), + metadata, + }); + } +} + +/// @brief 导出到C的tty初始化函数 +#[no_mangle] +pub extern "C" fn rs_tty_init() -> i32 { + let r = tty_init(); + if r.is_ok() { + return 0; + } else { + return r.unwrap_err().to_posix_errno(); + } +} + +/// @brief 初始化TTY设备 +pub fn tty_init() -> Result<(), SystemError> { + let tty: Arc = TtyDevice::new("tty0"); + let devfs_root_inode = ROOT_INODE().lookup("/dev"); + if devfs_root_inode.is_err() { + return Err(devfs_root_inode.unwrap_err()); + } + // 当前关闭键盘输入回显 + // TODO: 完善Termios之后, 改为默认开启键盘输入回显. + tty.core.disable_echo(); + let guard = TTY_DEVICES.upgradeable_read(); + + // 如果已经存在了这个设备 + if guard.contains_key("tty0") { + return Err(SystemError::EEXIST); + } + + let mut guard = guard.upgrade(); + + guard.insert("tty0".to_string(), tty.clone()); + + drop(guard); + + let r = devfs_register(&tty.name(), tty); + if r.is_err() { + return Err(devfs_root_inode.unwrap_err()); + } + + return Ok(()); } diff --git a/kernel/src/filesystem/devfs/mod.rs b/kernel/src/filesystem/devfs/mod.rs index 30d743a7..e4c1b2e8 100644 --- a/kernel/src/filesystem/devfs/mod.rs +++ b/kernel/src/filesystem/devfs/mod.rs @@ -10,7 +10,8 @@ use super::vfs::{ use crate::{ kerror, libs::spinlock::{SpinLock, SpinLockGuard}, - time::TimeSpec, syscall::SystemError, + syscall::SystemError, + time::TimeSpec, }; use alloc::{ collections::BTreeMap, @@ -94,9 +95,14 @@ impl DevFS { /// /// @param name 设备名称 /// @param device 设备节点的结构体 - pub fn register_device(&self, name: &str, device: Arc) -> Result<(), SystemError> { + pub fn register_device( + &self, + name: &str, + device: Arc, + ) -> Result<(), SystemError> { let dev_root_inode: Arc = self.root_inode.clone(); - match device.metadata().unwrap().file_type { + let metadata = device.metadata()?; + match metadata.file_type { // 字节设备挂载在 /dev/char FileType::CharDevice => { if let Err(_) = dev_root_inode.find("char") { @@ -108,8 +114,13 @@ impl DevFS { .as_any_ref() .downcast_ref::() .unwrap(); - + // 在 /dev/char 下创建设备节点 dev_char_inode.add_dev(name, device.clone())?; + + // 特殊处理 tty 设备,挂载在 /dev 下 + if name.starts_with("tty") && name.len() > 3 { + dev_root_inode.add_dev(name, device.clone())?; + } device.set_fs(dev_char_inode.0.lock().fs.clone()); } FileType::BlockDevice => { @@ -135,7 +146,11 @@ impl DevFS { } /// @brief 卸载设备 - pub fn unregister_device(&self, name: &str, device: Arc) -> Result<(), SystemError> { + pub fn unregister_device( + &self, + name: &str, + device: Arc, + ) -> Result<(), SystemError> { let dev_root_inode: Arc = self.root_inode.clone(); match device.metadata().unwrap().file_type { // 字节设备挂载在 /dev/char @@ -325,7 +340,11 @@ impl IndexNode for LockedDevFSInode { self } - fn open(&self, _data: &mut super::vfs::FilePrivateData, _mode: &FileMode) -> Result<(), SystemError> { + fn open( + &self, + _data: &mut super::vfs::FilePrivateData, + _mode: &FileMode, + ) -> Result<(), SystemError> { return Ok(()); } @@ -459,6 +478,7 @@ impl IndexNode for LockedDevFSInode { _buf: &mut [u8], _data: &mut super::vfs::file::FilePrivateData, ) -> Result { + kerror!("DevFS: read_at is not supported!"); Err(SystemError::ENOTSUP) } @@ -485,7 +505,7 @@ macro_rules! devfs_exact_ref { () => {{ let devfs_inode: Result, SystemError> = ROOT_INODE().find("dev"); if let Err(e) = devfs_inode { - kerror!("failed to get DevFS ref. errcode = {:?}",e); + kerror!("failed to get DevFS ref. errcode = {:?}", e); return Err(SystemError::ENOENT); } @@ -511,4 +531,3 @@ pub fn devfs_register(name: &str, device: Arc) -> Result<(), pub fn devfs_unregister(name: &str, device: Arc) -> Result<(), SystemError> { return devfs_exact_ref!().unregister_device(name, device); } - diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index d8313266..c18a4df4 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -62,7 +62,7 @@ bitflags! { const O_APPEND = 0o00002000; /// 非阻塞式IO模式 const O_NONBLOCK = 0o00004000; - /// used to be O_SYNC, see below + /// 每次write都等待物理I/O完成,但是如果写操作不影响读取刚写入的数据,则不等待文件属性更新 const O_DSYNC = 0o00010000; /// fcntl, for BSD compatibility const FASYNC = 0o00020000; @@ -76,9 +76,18 @@ bitflags! { const O_NOATIME = 0o01000000; /// set close_on_exec const O_CLOEXEC = 0o02000000; + /// 每次write都等到物理I/O完成,包括write引起的文件属性的更新 + const O_SYNC = 0o04000000; } } +impl FileMode { + /// @brief 获取文件的访问模式的值 + #[inline] + pub fn accmode(&self) -> u32 { + return self.bits() & FileMode::O_ACCMODE.bits(); + } +} /// @brief 抽象文件结构体 #[derive(Debug)] pub struct File { @@ -128,7 +137,6 @@ impl File { if buf.len() < len { return Err(SystemError::ENOBUFS); } - let len = self .inode .read_at(self.offset, len, buf, &mut self.private_data)?; @@ -151,7 +159,7 @@ impl File { } let len = self .inode - .write_at(self.offset, len, buf, &mut FilePrivateData::Unused)?; + .write_at(self.offset, len, buf, &mut self.private_data)?; self.offset += len; return Ok(len); } diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index dde774cc..95e6ee2e 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -15,7 +15,7 @@ use crate::{ syscall::SystemError, }; -use self::file::FileMode; +use self::{core::generate_inode_id, file::FileMode}; pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS}; /// vfs容许的最大的路径名称长度 @@ -234,9 +234,9 @@ pub trait IndexNode: Any + Sync + Send + Debug { } /// @brief 删除文件夹 - /// + /// /// @param name 文件夹名称 - /// + /// /// @return 成功 Ok(()) /// @return 失败 Err(错误码) fn rmdir(&self, _name: &str) ->Result<(), SystemError>{ @@ -332,6 +332,11 @@ pub trait IndexNode: Any + Sync + Send + Debug { fn truncate(&self, _len: usize) -> Result<(), SystemError> { return Err(SystemError::ENOTSUP); } + + /// @brief 将当前inode的内容同步到具体设备上 + fn sync(&self) -> Result<(), SystemError> { + return Ok(()); + } } impl dyn IndexNode { @@ -516,3 +521,24 @@ pub struct Dirent { d_type: u8, // entry的类型 d_name: u8, // 文件entry的名字(是一个零长数组), 本字段仅用于占位 } + +impl Metadata { + pub fn new(file_type: FileType, mode: u32) -> Self { + Metadata { + dev_id: 0, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type, + mode, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: 0, + } + } +} diff --git a/kernel/src/filesystem/vfs/mount.rs b/kernel/src/filesystem/vfs/mount.rs index cb74c239..f368d75c 100644 --- a/kernel/src/filesystem/vfs/mount.rs +++ b/kernel/src/filesystem/vfs/mount.rs @@ -164,11 +164,11 @@ impl IndexNode for MountFSInode { offset: usize, len: usize, buf: &[u8], - _data: &mut FilePrivateData, + data: &mut FilePrivateData, ) -> Result { return self .inner_inode - .write_at(offset, len, buf, &mut FilePrivateData::Unused); + .write_at(offset, len, buf, data); } #[inline] diff --git a/kernel/src/include/bindings/wrapper.h b/kernel/src/include/bindings/wrapper.h index 4b8c42db..36a0c0b8 100644 --- a/kernel/src/include/bindings/wrapper.h +++ b/kernel/src/include/bindings/wrapper.h @@ -26,22 +26,21 @@ #include #include #include +#include #include #include -#include #include #include #include +#include #include #include +#include +#include #include #include #include #include #include -#include