From 52da9a59374752b4d01907b052135a0d317781dd Mon Sep 17 00:00:00 2001 From: GnoCiYeH Date: Mon, 26 Feb 2024 15:27:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=B8=8ELinux=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E7=9A=84Ntty=20(#517)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 已经完成的功能: - 写:printf能够正常在tty输出 - 读:与键盘驱动接上 - 信号: 能够正常通过ctrl向前台进程发送信号 * 支持目前的shell,改动printk使其与新版tty兼容。 * 删除原有tty文件夹,并更改新tty文件名 * 添加clear清屏程序 * 实现tty部分ioctl,更改部分问题 --- kernel/crates/bitmap/src/bitmap_core.rs | 1 + kernel/crates/bitmap/src/static_bitmap.rs | 1 + kernel/crates/system_error/src/lib.rs | 2 + kernel/src/arch/x86_64/mm/mod.rs | 2 +- .../src/driver/base/device/device_number.rs | 4 +- kernel/src/driver/keyboard/ps2_keyboard.rs | 14 +- kernel/src/driver/mod.rs | 1 + kernel/src/driver/{tty => }/serial/mod.rs | 5 +- .../driver/{tty => }/serial/serial8250/mod.rs | 53 +- .../serial/serial8250/serial8250_pio.rs | 2 +- kernel/src/driver/tty/console.rs | 125 + kernel/src/driver/tty/init.rs | 7 - kernel/src/driver/tty/mod.rs | 435 +--- kernel/src/driver/tty/termios.rs | 383 ++++ kernel/src/driver/tty/tty_core.rs | 592 +++++ kernel/src/driver/tty/tty_device.rs | 701 +++--- kernel/src/driver/tty/tty_driver.rs | 475 +++- kernel/src/driver/tty/tty_job_control.rs | 139 ++ kernel/src/driver/tty/tty_ldisc/mod.rs | 117 + kernel/src/driver/tty/tty_ldisc/ntty.rs | 2016 +++++++++++++++++ kernel/src/driver/tty/tty_port.rs | 113 + .../tty/virtual_terminal/console_map.rs | 135 ++ kernel/src/driver/tty/virtual_terminal/mod.rs | 303 +++ .../tty/virtual_terminal/virtual_console.rs | 2015 ++++++++++++++++ kernel/src/driver/tty/vt/mod.rs | 10 - kernel/src/driver/video/fbdev/base/fbcmap.rs | 1 + .../fbdev/base/fbcon/framebuffer_console.rs | 787 +++++++ .../fbdev/base/{fbcon.rs => fbcon/mod.rs} | 183 +- kernel/src/driver/video/fbdev/base/mod.rs | 423 +++- kernel/src/driver/video/fbdev/vesafb.rs | 256 ++- kernel/src/driver/video/mod.rs | 6 +- kernel/src/filesystem/devfs/mod.rs | 9 +- kernel/src/filesystem/kernfs/mod.rs | 7 +- kernel/src/filesystem/vfs/file.rs | 2 +- kernel/src/filesystem/vfs/mod.rs | 7 +- kernel/src/filesystem/vfs/mount.rs | 9 +- kernel/src/filesystem/vfs/syscall.rs | 5 +- kernel/src/init/init.rs | 4 +- kernel/src/libs/font/bin/VGA_8X16.bytes | Bin 0 -> 4096 bytes kernel/src/libs/font/bin/VGA_8X8.bytes | Bin 0 -> 2048 bytes kernel/src/libs/font/font_type/mod.rs | 2 + kernel/src/libs/font/font_type/vga8x16.rs | 10 + kernel/src/libs/font/font_type/vga8x8.rs | 11 + kernel/src/libs/font/mod.rs | 49 + kernel/src/libs/keyboard_parser.rs | 118 +- kernel/src/libs/lib_ui/screen_manager.rs | 4 +- kernel/src/libs/lib_ui/textui.rs | 30 +- kernel/src/libs/lib_ui/textui_no_alloc.rs | 2 +- kernel/src/libs/mod.rs | 2 + kernel/src/libs/printk.rs | 38 +- kernel/src/mm/init.rs | 2 +- kernel/src/process/mod.rs | 12 + kernel/src/syscall/mod.rs | 19 + kernel/src/virt/kvm/kvm_dev.rs | 7 +- kernel/src/virt/kvm/vcpu_dev.rs | 7 +- kernel/src/virt/kvm/vm_dev.rs | 7 +- user/apps/clear/.gitignore | 3 + user/apps/clear/Cargo.toml | 10 + user/apps/clear/Makefile | 56 + user/apps/clear/README.md | 7 + user/apps/clear/src/main.rs | 3 + user/dadk/config/clear-0.1.0.dadk | 22 + 62 files changed, 8843 insertions(+), 928 deletions(-) rename kernel/src/driver/{tty => }/serial/mod.rs (95%) rename kernel/src/driver/{tty => }/serial/serial8250/mod.rs (92%) rename kernel/src/driver/{tty => }/serial/serial8250/serial8250_pio.rs (99%) create mode 100644 kernel/src/driver/tty/console.rs delete mode 100644 kernel/src/driver/tty/init.rs create mode 100644 kernel/src/driver/tty/termios.rs create mode 100644 kernel/src/driver/tty/tty_core.rs create mode 100644 kernel/src/driver/tty/tty_job_control.rs create mode 100644 kernel/src/driver/tty/tty_ldisc/mod.rs create mode 100644 kernel/src/driver/tty/tty_ldisc/ntty.rs create mode 100644 kernel/src/driver/tty/tty_port.rs create mode 100644 kernel/src/driver/tty/virtual_terminal/console_map.rs create mode 100644 kernel/src/driver/tty/virtual_terminal/mod.rs create mode 100644 kernel/src/driver/tty/virtual_terminal/virtual_console.rs delete mode 100644 kernel/src/driver/tty/vt/mod.rs create mode 100644 kernel/src/driver/video/fbdev/base/fbcmap.rs create mode 100644 kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs rename kernel/src/driver/video/fbdev/base/{fbcon.rs => fbcon/mod.rs} (64%) create mode 100644 kernel/src/libs/font/bin/VGA_8X16.bytes create mode 100644 kernel/src/libs/font/bin/VGA_8X8.bytes create mode 100644 kernel/src/libs/font/font_type/mod.rs create mode 100644 kernel/src/libs/font/font_type/vga8x16.rs create mode 100644 kernel/src/libs/font/font_type/vga8x8.rs create mode 100644 kernel/src/libs/font/mod.rs create mode 100644 user/apps/clear/.gitignore create mode 100644 user/apps/clear/Cargo.toml create mode 100644 user/apps/clear/Makefile create mode 100644 user/apps/clear/README.md create mode 100644 user/apps/clear/src/main.rs create mode 100644 user/dadk/config/clear-0.1.0.dadk diff --git a/kernel/crates/bitmap/src/bitmap_core.rs b/kernel/crates/bitmap/src/bitmap_core.rs index 1a4d79a3..da80adf8 100644 --- a/kernel/crates/bitmap/src/bitmap_core.rs +++ b/kernel/crates/bitmap/src/bitmap_core.rs @@ -2,6 +2,7 @@ use core::{intrinsics::unlikely, marker::PhantomData}; use crate::traits::BitOps; +#[derive(Debug, Clone)] pub(crate) struct BitMapCore { phantom: PhantomData, } diff --git a/kernel/crates/bitmap/src/static_bitmap.rs b/kernel/crates/bitmap/src/static_bitmap.rs index dc9b4546..96281aaf 100644 --- a/kernel/crates/bitmap/src/static_bitmap.rs +++ b/kernel/crates/bitmap/src/static_bitmap.rs @@ -5,6 +5,7 @@ use crate::{bitmap_core::BitMapCore, traits::BitMapOps}; /// 静态位图 /// /// 该位图的大小在编译时确定,不可变 +#[derive(Debug, Clone)] pub struct StaticBitmap where [(); (N + usize::BITS as usize - 1) / (usize::BITS as usize)]:, diff --git a/kernel/crates/system_error/src/lib.rs b/kernel/crates/system_error/src/lib.rs index 958042a0..a8b9e55d 100644 --- a/kernel/crates/system_error/src/lib.rs +++ b/kernel/crates/system_error/src/lib.rs @@ -285,6 +285,8 @@ pub enum SystemError { EVMPRTLDFailed = 517, EVMLAUNCHFailed = 518, KVM_HVA_ERR_BAD = 519, + /// 没有对应的ioctlcmd + ENOIOCTLCMD = 520, } impl SystemError { diff --git a/kernel/src/arch/x86_64/mm/mod.rs b/kernel/src/arch/x86_64/mm/mod.rs index 0d2f5e7c..c76fa52d 100644 --- a/kernel/src/arch/x86_64/mm/mod.rs +++ b/kernel/src/arch/x86_64/mm/mod.rs @@ -7,7 +7,7 @@ use hashbrown::HashSet; use x86::time::rdtsc; use x86_64::registers::model_specific::EferFlags; -use crate::driver::tty::serial::serial8250::send_to_default_serial8250_port; +use crate::driver::serial::serial8250::send_to_default_serial8250_port; use crate::include::bindings::bindings::{ multiboot2_get_load_base, multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t, multiboot_tag_load_base_addr_t, diff --git a/kernel/src/driver/base/device/device_number.rs b/kernel/src/driver/base/device/device_number.rs index fd28c702..98d90ff5 100644 --- a/kernel/src/driver/base/device/device_number.rs +++ b/kernel/src/driver/base/device/device_number.rs @@ -1,4 +1,4 @@ -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct Major(u32); impl Major { @@ -10,6 +10,8 @@ impl Major { pub const UNNAMED_MAJOR: Self = Self::new(0); pub const IDE0_MAJOR: Self = Self::new(3); + pub const TTY_MAJOR: Self = Self::new(4); + pub const TTYAUX_MAJOR: Self = Self::new(5); pub const HD_MAJOR: Self = Self::IDE0_MAJOR; pub const INPUT_MAJOR: Self = Self::new(13); diff --git a/kernel/src/driver/keyboard/ps2_keyboard.rs b/kernel/src/driver/keyboard/ps2_keyboard.rs index 513b4873..1a011d55 100644 --- a/kernel/src/driver/keyboard/ps2_keyboard.rs +++ b/kernel/src/driver/keyboard/ps2_keyboard.rs @@ -3,10 +3,7 @@ use core::{ffi::c_void, sync::atomic::AtomicI32}; use alloc::sync::{Arc, Weak}; use crate::{ - driver::{ - base::device::device_number::{DeviceNumber, Major}, - tty::tty_device::TTY_DEVICES, - }, + driver::base::device::device_number::{DeviceNumber, Major}, filesystem::{ devfs::{devfs_register, DevFS, DeviceINode}, vfs::{ @@ -23,14 +20,7 @@ use system_error::SystemError; pub struct LockedPS2KeyBoardInode(RwLock, AtomicI32); // self.1 用来记录有多少个文件打开了这个inode lazy_static! { - 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)) - }; + static ref PS2_KEYBOARD_FSM: SpinLock = SpinLock::new(TypeOneFSM::new()); } #[derive(Debug)] diff --git a/kernel/src/driver/mod.rs b/kernel/src/driver/mod.rs index 0a8a5608..a372c27e 100644 --- a/kernel/src/driver/mod.rs +++ b/kernel/src/driver/mod.rs @@ -7,6 +7,7 @@ pub mod keyboard; pub mod net; pub mod open_firmware; pub mod pci; +pub mod serial; pub mod timers; pub mod tty; pub mod video; diff --git a/kernel/src/driver/tty/serial/mod.rs b/kernel/src/driver/serial/mod.rs similarity index 95% rename from kernel/src/driver/tty/serial/mod.rs rename to kernel/src/driver/serial/mod.rs index d96c618a..53af56d8 100644 --- a/kernel/src/driver/tty/serial/mod.rs +++ b/kernel/src/driver/serial/mod.rs @@ -7,11 +7,9 @@ use crate::{driver::base::device::device_number::DeviceNumber, mm::VirtAddr}; use self::serial8250::serial8250_manager; -use super::tty_driver::TtyDriver; - pub mod serial8250; -pub trait UartDriver: Debug + Send + Sync + TtyDriver { +pub trait UartDriver: Debug + Send + Sync { fn device_number(&self) -> DeviceNumber; /// 获取最大的设备数量 @@ -56,6 +54,7 @@ impl UartManager { /// todo: 把uart设备注册到tty层 /// /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/serial/serial_core.c?fi=uart_register_driver#2720 + #[allow(dead_code)] pub fn register_driver(&self, _driver: &Arc) -> Result<(), SystemError> { return Ok(()); } diff --git a/kernel/src/driver/tty/serial/serial8250/mod.rs b/kernel/src/driver/serial/serial8250/mod.rs similarity index 92% rename from kernel/src/driver/tty/serial/serial8250/mod.rs rename to kernel/src/driver/serial/serial8250/mod.rs index 5245c767..f9c39f5e 100644 --- a/kernel/src/driver/tty/serial/serial8250/mod.rs +++ b/kernel/src/driver/serial/serial8250/mod.rs @@ -11,23 +11,17 @@ use alloc::{ use system_error::SystemError; use crate::{ - driver::{ - base::{ - class::Class, - device::{ - bus::Bus, device_manager, device_number::DeviceNumber, driver::Driver, Device, - DeviceKObjType, DeviceState, DeviceType, IdTable, - }, - kobject::{KObjType, KObject, KObjectState, LockedKObjectState}, - kset::KSet, - platform::{ - platform_device::{platform_device_manager, PlatformDevice}, - platform_driver::{platform_driver_manager, PlatformDriver}, - }, + driver::base::{ + class::Class, + device::{ + bus::Bus, device_manager, device_number::DeviceNumber, driver::Driver, Device, + DeviceKObjType, DeviceState, DeviceType, IdTable, }, - tty::{ - tty_device::TtyDevice, - tty_driver::{TtyDriver, TtyDriverMetadata, TtyDriverOperations}, + kobject::{KObjType, KObject, KObjectState, LockedKObjectState}, + kset::KSet, + platform::{ + platform_device::{platform_device_manager, PlatformDevice}, + platform_driver::{platform_driver_manager, PlatformDriver}, }, }, filesystem::kernfs::KernFSInode, @@ -377,6 +371,7 @@ impl InnerSerial8250ISADriver { #[derive(Debug)] #[cast_to([sync] Driver, PlatformDriver)] +#[allow(dead_code)] struct Serial8250ISADriver { inner: RwLock, name: &'static str, @@ -402,32 +397,6 @@ impl Serial8250ISADriver { } } -impl TtyDriver for Serial8250ISADriver { - fn driver_name(&self) -> &str { - self.name - } - - fn dev_name(&self) -> &str { - todo!() - } - - fn metadata(&self) -> &TtyDriverMetadata { - todo!() - } - - fn other(&self) -> Option<&Arc> { - todo!() - } - - fn ttys(&self) -> &[Arc] { - todo!() - } - - fn tty_ops(&self) -> Option<&'static dyn TtyDriverOperations> { - None - } -} - impl UartDriver for Serial8250ISADriver { fn device_number(&self) -> DeviceNumber { todo!() diff --git a/kernel/src/driver/tty/serial/serial8250/serial8250_pio.rs b/kernel/src/driver/serial/serial8250/serial8250_pio.rs similarity index 99% rename from kernel/src/driver/tty/serial/serial8250/serial8250_pio.rs rename to kernel/src/driver/serial/serial8250/serial8250_pio.rs index c2a0d354..77b2bd69 100644 --- a/kernel/src/driver/tty/serial/serial8250/serial8250_pio.rs +++ b/kernel/src/driver/serial/serial8250/serial8250_pio.rs @@ -9,7 +9,7 @@ use alloc::sync::{Arc, Weak}; use crate::{ arch::{io::PortIOArch, CurrentPortIOArch}, - driver::tty::serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort}, + driver::serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort}, libs::rwlock::RwLock, }; use system_error::SystemError; diff --git a/kernel/src/driver/tty/console.rs b/kernel/src/driver/tty/console.rs new file mode 100644 index 00000000..d9df2f7f --- /dev/null +++ b/kernel/src/driver/tty/console.rs @@ -0,0 +1,125 @@ +use system_error::SystemError; + +use super::virtual_terminal::virtual_console::{ + CursorOperation, ScrollDir, VirtualConsoleData, VirtualConsoleIntensity, +}; + +/// 终端切换相关的回调 +pub trait ConsoleSwitch: Sync + Send { + /// 初始化,会对vc_data进行一系列初始化操作 + fn con_init(&self, vc_data: &mut VirtualConsoleData, init: bool) -> Result<(), SystemError>; + + /// 进行释放等系列操作,目前未使用 + fn con_deinit(&self) -> Result<(), SystemError>; + + /// ## 清空console的一片区域 + /// 该函数的所有参数对应的都是以字符为单位 + /// ### 参数: + /// - vc_data: 对应的ConsoleData + /// - sy: 对应区域左上角的y轴 + /// - sx: 对应区域左上角的x轴 + /// - height: 区域高度 + /// - width: 区域宽度 + fn con_clear( + &self, + vc_data: &mut VirtualConsoleData, + sy: usize, + sx: usize, + height: usize, + width: usize, + ) -> Result<(), SystemError>; + + /// ## 向console输出一个字符 + /// ### 参数: + /// - vc_data: 对应的ConsoleData + /// - ch: 数据 + /// - ypos: 起始y坐标 + /// - xpos: 起始x坐标 + fn con_putc( + &self, + vc_data: &VirtualConsoleData, + ch: u16, + ypos: u32, + xpos: u32, + ) -> Result<(), SystemError>; + + /// ## 向console输出一串字符 + /// ### 参数: + /// - vc_data: 对应的ConsoleData + /// - buf: 数据 + /// - count: 输出字符数量 + /// - ypos: 起始y坐标 + /// - xpos: 起始x坐标 + fn con_putcs( + &self, + vc_data: &VirtualConsoleData, + buf: &[u16], + count: usize, + ypos: u32, + xpos: u32, + ) -> Result<(), SystemError>; + + /// ## 根据pos计算出对应xy + /// + /// ### 返回值: (下一行的起始偏移,x,y) + fn con_getxy( + &self, + _vc_data: &VirtualConsoleData, + _pos: usize, + ) -> Result<(usize, usize, usize), SystemError> { + return Err(SystemError::ENOSYS); + } + + /// ## 对光标进行操作 + /// ### 参数: + /// - vc_data: 对应的ConsoleData + /// - op: 对光标的操作 + fn con_cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation); + + /// ## 根据参数构建出对应的属性 + /// ### 参数: + /// - vc_data: 对应的ConsoleData + /// - color: 颜色 + /// - intensity: 字符强度 + /// - blink: 是否闪烁 + /// - underline: 下划线 + /// - reverse: 颜色反转 + /// - italic: 斜体 + fn con_build_attr( + &self, + _vc_data: &VirtualConsoleData, + _color: u8, + _intensity: VirtualConsoleIntensity, + _blink: bool, + _underline: bool, + _reverse: bool, + _italic: bool, + ) -> Result { + return Err(SystemError::ENOSYS); + } + + /// ## 设置调色板 + /// ### 参数: + /// - vc_data: 对应的ConsoleData + /// - color_table: 颜色表 + fn con_set_palette( + &self, + vc_data: &VirtualConsoleData, + color_table: &[u8], + ) -> Result<(), SystemError>; + + /// ## 滚动 + /// ### 参数 + /// - top:滚动范围顶部 + /// - bottom: 滚动范围底部 + /// - dir: 滚动方向 + /// - nr: 滚动行数 + fn con_scroll( + &self, + vc_data: &mut VirtualConsoleData, + top: usize, + bottom: usize, + dir: ScrollDir, + nr: usize, + ) -> bool; +} diff --git a/kernel/src/driver/tty/init.rs b/kernel/src/driver/tty/init.rs deleted file mode 100644 index 13d087e1..00000000 --- a/kernel/src/driver/tty/init.rs +++ /dev/null @@ -1,7 +0,0 @@ -use super::serial::serial_early_init; -use system_error::SystemError; - -pub fn tty_early_init() -> Result<(), SystemError> { - serial_early_init()?; - return Ok(()); -} diff --git a/kernel/src/driver/tty/mod.rs b/kernel/src/driver/tty/mod.rs index 692ea4ec..662a1d10 100644 --- a/kernel/src/driver/tty/mod.rs +++ b/kernel/src/driver/tty/mod.rs @@ -1,418 +1,37 @@ -use core::intrinsics::unlikely; +use alloc::vec::Vec; -use alloc::string::String; - -use kdepends::thingbuf::mpsc::{ - self, - errors::{TryRecvError, TrySendError}, -}; - -use crate::libs::rwlock::RwLock; - -pub mod init; -pub mod serial; +pub mod console; +pub mod termios; +pub mod tty_core; pub mod tty_device; pub mod tty_driver; -pub mod vt; +pub mod tty_job_control; +pub mod tty_ldisc; +pub mod tty_port; +pub mod virtual_terminal; -bitflags! { - pub struct TtyCoreState: u32{ - /// 在读取stdin缓冲区时,由于队列为空,有读者被阻塞 - const BLOCK_AT_STDIN_READ = (1 << 0); - /// 开启输入回显。 - const ECHO_ON = (1 << 1); - } - - #[derive(Default)] - pub struct TtyFileFlag:u32{ - /// 当前文件是stdin文件 - const STDIN = (1 << 0); - /// 当前文件是stdout文件 - const STDOUT = (1 << 1); - /// 当前文件是stderr文件 - const STDERR = (1 << 2); - } -} - -/// @brief tty文件的私有信息 -#[derive(Debug, Default, Clone)] -pub struct TtyFilePrivateData { - flags: TtyFileFlag, -} - -/// @brief tty设备的核心功能结构体。在此结构体的基础上,衍生出TTY/PTY/PTS等 -/// -/// 每个TTY Core有5个端口: -/// - stdin:连接到一个活动进程的stdin文件描述符 -/// - stdout:连接到多个进程的stdout文件描述符 -/// - stderr:连接到多个进程的stdout文件描述符 -/// - 输入端口:向tty设备输入数据的接口。输入到该接口的数据,将被导向stdin接口。 -/// 如果开启了回显,那么,数据也将同时被导向输出端 -/// - 输出端口:tty设备对外输出数据的端口。从stdout、stderr输入的数据,将会被导向此端口。 -/// 此端口可以连接到屏幕、文件、或者是另一个tty core的输入端口。如果开启了 -/// 输入数据回显,那么,输入端口的数据,将会被同时导向此端口,以及stdin端口 -#[derive(Debug)] -struct TtyCore { - /// stdin的mpsc队列输入输出端 - stdin_rx: mpsc::Receiver, - stdin_tx: mpsc::Sender, - /// 输出的mpsc队列输入输出端 - output_rx: mpsc::Receiver, - output_tx: mpsc::Sender, - // 前台进程,以后改成前台进程组 - // front_job: Option, - /// tty核心的状态 - state: RwLock, -} - -#[derive(Debug)] +// 下列结构体暂时放在这 +/// 键盘/显示器"(Keyboard/Display)模式 #[allow(dead_code)] -pub enum TtyError { - /// 缓冲区满,返回成功传送的字节数 - BufferFull(usize), - /// 缓冲区空,返回成功传送的字节数 - BufferEmpty(usize), - /// 设备已经被关闭 - Closed, - /// End of file(已经读取的字符数,包含eof) - EOF(usize), - /// 接收到信号终止 - Stopped(usize), - Unknown(String), +#[derive(Debug, PartialEq, Clone)] +pub enum KDMode { + KdText, + KdGraphics, + KdText0, + KdText1, + Undefined, } -impl TtyCore { - // 各个缓冲区的大小 - pub const STDIN_BUF_SIZE: usize = 4096; - pub const OUTPUT_BUF_SIZE: usize = 4096; - - /// @brief 创建一个TTY核心组件 - pub fn new() -> TtyCore { - let (stdin_tx, stdin_rx) = mpsc::channel::(Self::STDIN_BUF_SIZE); - let (output_tx, output_rx) = mpsc::channel::(Self::OUTPUT_BUF_SIZE); - let state: RwLock = RwLock::new(TtyCoreState { bits: 0 }); - - return TtyCore { - stdin_rx, - stdin_tx, - output_rx, - output_tx, - state, - }; - } - - /// @brief 向tty的输入端口输入数据 - /// - /// @param buf 输入数据 - /// - /// @param block 是否允许阻塞 - /// - /// @return Ok(成功传送的字节数) - /// @return Err(TtyError) 内部错误信息 - pub fn input(&self, buf: &[u8], block: bool) -> Result { - let val = self.write_stdin(buf, block)?; - // 如果开启了输入回显,那么就写一份到输出缓冲区 - if self.echo_enabled() { - self.write_output(&buf[0..val], true)?; - } - return Ok(val); - } - - /// @brief 从tty的输出端口读出数据 - /// - /// @param buf 输出缓冲区 - /// - /// @return Ok(成功传送的字节数) - /// @return Err(TtyError) 内部错误信息 - #[inline] - pub fn output(&self, buf: &mut [u8], block: bool) -> Result { - return self.read_output(buf, block); - } - - /// @brief tty的stdout接口 - /// - /// @param buf 输入缓冲区 - /// - /// @return Ok(成功传送的字节数) - /// @return Err(TtyError) 内部错误信息 - #[inline] - pub fn stdout(&self, buf: &[u8], block: bool) -> Result { - return self.write_output(buf, block); - } - - /// @brief tty的stderr接口 - /// - /// @param buf 输入缓冲区 - /// - /// @return Ok(成功传送的字节数) - /// @return Err(TtyError) 内部错误信息 - #[inline] - pub fn stderr(&self, buf: &[u8], block: bool) -> Result { - return self.write_output(buf, block); - } - - /// @brief 读取TTY的stdin缓冲区 - /// - /// @param buf 读取到的位置 - /// @param block 是否阻塞读 - /// - /// @return Ok(成功读取的字节数) - /// @return Err(TtyError) 内部错误信息 - pub fn read_stdin(&self, buf: &mut [u8], block: bool) -> Result { - // TODO: 增加对EOF的处理 - let mut cnt = 0; - while cnt < buf.len() { - let val: Result, TryRecvError> = self.stdin_rx.try_recv_ref(); - if let Err(err) = val { - match err { - TryRecvError::Closed => return Err(TtyError::Closed), - TryRecvError::Empty => { - if block { - continue; - } else { - return Ok(cnt); - } - } - _ => return Err(TtyError::Unknown(format!("{err:?}"))), - } - } else { - let x = *val.unwrap(); - buf[cnt] = x; - cnt += 1; - - if unlikely(self.stdin_should_return(x)) { - return Ok(cnt); - } - } - } - return Ok(cnt); - } - - fn stdin_should_return(&self, c: u8) -> bool { - // 如果是换行符或者是ctrl+d,那么就应该返回 - return c == b'\n' || c == 4; - } - - /// @brief 向stdin缓冲区内写入数据 - /// - /// @param buf 输入缓冲区 - /// - /// @param block 当缓冲区满的时候,是否阻塞 - /// - /// @return Ok(成功传送的字节数) - /// @return Err(BufferFull(成功传送的字节数)) 缓冲区满,成功传送的字节数 - /// @return Err(TtyError) 内部错误信息 - fn write_stdin(&self, buf: &[u8], block: bool) -> Result { - let mut cnt = 0; - while cnt < buf.len() { - let r: Result, TrySendError> = self.stdin_tx.try_send_ref(); - if let Err(e) = r { - match e { - TrySendError::Closed(_) => return Err(TtyError::Closed), - TrySendError::Full(_) => { - if block { - continue; - } else { - return Err(TtyError::BufferFull(cnt)); - } - } - _ => return Err(TtyError::Unknown(format!("{e:?}"))), - } - } else { - *r.unwrap() = buf[cnt]; - cnt += 1; - } - } - - return Ok(cnt); - } - - /// @brief 读取TTY的output缓冲区 - /// - /// @param buf 读取到的位置 - /// @param block 是否阻塞读 - /// - /// @return Ok(成功读取的字节数) - /// @return Err(TtyError) 内部错误信息 - fn read_output(&self, buf: &mut [u8], block: bool) -> Result { - let mut cnt = 0; - while cnt < buf.len() { - let val: Result, TryRecvError> = self.output_rx.try_recv_ref(); - if let Err(err) = val { - match err { - TryRecvError::Closed => return Err(TtyError::Closed), - TryRecvError::Empty => { - if block { - continue; - } else { - return Ok(cnt); - } - } - _ => return Err(TtyError::Unknown(format!("{err:?}"))), - } - } else { - buf[cnt] = *val.unwrap(); - cnt += 1; - } - } - return Ok(cnt); - } - - /// @brief 向output缓冲区内写入数据 - /// - /// @param buf 输入缓冲区 - /// - /// @param block 当缓冲区满的时候,是否阻塞 - /// - /// @return Ok(成功传送的字节数) - /// @return Err(BufferFull(成功传送的字节数)) 缓冲区满,成功传送的字节数 - /// @return Err(TtyError) 内部错误信息 - fn write_output(&self, buf: &[u8], block: bool) -> Result { - let mut cnt = 0; - while cnt < buf.len() { - let r: Result, TrySendError> = self.output_tx.try_send_ref(); - if let Err(e) = r { - match e { - TrySendError::Closed(_) => return Err(TtyError::Closed), - TrySendError::Full(_) => { - if block { - continue; - } else { - return Err(TtyError::BufferFull(cnt)); - } - } - _ => return Err(TtyError::Unknown(format!("{e:?}"))), - } - } else { - // TODO: 在这里考虑增加对信号发送的处理 - // if buf[cnt] == 3 { - // let pid = ProcessManager::current_pcb().pid(); - // Signal::SIGKILL.send_signal_info( - // Some(&mut SigInfo::new( - // Signal::SIGKILL, - // 0, - // SigCode::SI_USER, - // SigType::Kill(pid), - // )), - // pid, - // ); - // return Err(TtyError::Stopped(cnt)); - // } - *r.unwrap() = buf[cnt]; - cnt += 1; - } - } - return Ok(cnt); - } - - /// @brief 开启tty输入回显(也就是将输入数据传送一份到输出缓冲区) - #[inline] - pub fn enable_echo(&self) { - self.state.write().set(TtyCoreState::ECHO_ON, true); - } - - /// @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); +impl Default for KDMode { + fn default() -> Self { + Self::Undefined } } -// ======= 以下代码考虑了“缓冲区满,然后睡眠,当缓冲区有空位就唤醒”的逻辑。 -// 但是由于在开发过程中的调整,并且由于数据结构发生变化,因此暂时不实现上述优化,因此先注释。 -// -// @brief 读取TTY的stdin缓冲区 -// -// @param buf 读取到的位置 -// @param block 是否阻塞读 -// -// @return Ok(成功读取的字节数) -// @return Err(TtyError) 内部错误信息 -// pub fn read_stdin(&mut self, buf: &mut [u8], block: bool) -> Result { -// let mut cnt = 0; -// loop{ -// if cnt == buf.len(){ -// break; -// } -// let val:Option = self.stdin_queue.dequeue(); -// // 如果没读到 -// if val.is_none() { -// // 如果阻塞读 -// if block { -// let state_guard: RwLockUpgradableGuard = -// self.state.upgradeable_read(); -// // 判断是否有进程正在stdin上睡眠,如果有,则忙等读 -// // 理论上,这种情况应该不存在,因为stdin是单读者的 -// if state_guard.contains(TtyCoreState::BLOCK_AT_STDIN_READ) { -// kwarn!("Read stdin: Process {} want to read its' stdin, but previous process {} is sleeping on the stdin.", current_pcb().pid, self.stdin_waiter.read().as_ref().unwrap().pid); -// drop(state_guard); -// Self::ringbuf_spin_dequeue(&mut buf[cnt], &mut self.stdin_queue); -// cnt += 1; -// } else { -// // 正常情况,阻塞读,将当前进程休眠 -// let mut state_guard: RwLockWriteGuard = state_guard.upgrade(); -// let mut stdin_waiter_guard: RwLockWriteGuard< -// Option<&mut process_control_block>, -// > = self.stdin_waiter.write(); - -// // 由于输入数据到stdin的时候,必须先获得state guard的读锁。而这里我们已经获取了state的写锁。 -// // 因此可以保证,此时没有新的数据会进入stdin_queue. 因此再次尝试读取stdin_queue -// let val:Option = self.stdin_queue.dequeue(); -// // 读到数据,不用睡眠 -// if val.is_some(){ -// buf[cnt] = val.unwrap(); -// cnt += 1; -// continue; -// } -// // 没读到数据,准备睡眠 - -// // 设置等待标志位 -// state_guard.set(TtyCoreState::BLOCK_AT_STDIN_READ, true); - -// // 将当前进程标记为被其他机制管理 -// unsafe { -// current_pcb().mark_sleep_interruptible(); -// } - -// *stdin_waiter_guard = Some(current_pcb()); -// drop(stdin_waiter_guard); -// drop(state_guard); -// sched(); -// continue; -// } -// } else { -// // 非阻塞读,没读到就直接返回了 -// return Ok(cnt); -// } -// }else{ -// buf[cnt] = val.unwrap(); -// cnt += 1; -// } -// } - -// return Ok(cnt); -// } - -// fn write_stdin(&self) - -// /// @brief 非休眠的,自旋地读队列,直到有元素被读出来 -// fn ringbuf_spin_dequeue(dst: &mut u8, queue: &mut AllocRingBuffer) { -// loop { -// if let Some(val) = queue.dequeue() { -// *dst = val; -// return; -// } -// } -// } +#[derive(Debug, Default, Clone)] +pub struct ConsoleFont { + pub width: u32, + pub height: u32, + pub count: u32, + pub data: Vec, +} diff --git a/kernel/src/driver/tty/termios.rs b/kernel/src/driver/tty/termios.rs new file mode 100644 index 00000000..ef7dee54 --- /dev/null +++ b/kernel/src/driver/tty/termios.rs @@ -0,0 +1,383 @@ +use super::tty_ldisc::LineDisciplineType; + +/// ## 窗口大小 +#[repr(C)] +#[derive(Debug, Default, Clone, Copy)] +pub struct WindowSize { + /// 行 + pub row: u16, + /// 列 + pub col: u16, + /// x方向像素数 + pub xpixel: u16, + /// y方向像素数 + pub ypixel: u16, +} + +#[derive(Debug, Clone, Copy)] +pub struct Termios { + pub input_mode: InputMode, + pub output_mode: OutputMode, + pub control_mode: ControlMode, + pub local_mode: LocalMode, + pub control_characters: [u8; CONTORL_CHARACTER_NUM], + pub line: LineDisciplineType, + pub input_speed: u32, + pub output_speed: u32, +} + +#[derive(Clone, Copy)] +pub struct PosixTermios { + pub c_iflag: u32, + pub c_oflag: u32, + pub c_cflag: u32, + pub c_lflag: u32, + pub c_cc: [u8; CONTORL_CHARACTER_NUM], + pub c_line: u8, + pub c_ispeed: u32, + pub c_ospeed: u32, +} + +impl PosixTermios { + pub fn from_kernel_termios(termios: Termios) -> Self { + Self { + c_iflag: termios.input_mode.bits, + c_oflag: termios.output_mode.bits, + c_cflag: termios.control_mode.bits, + c_lflag: termios.local_mode.bits, + c_cc: termios.control_characters.clone(), + c_line: termios.line as u8, + c_ispeed: termios.input_speed, + c_ospeed: termios.output_speed, + } + } + + #[allow(dead_code)] + pub fn to_kernel_termios(&self) -> Termios { + Termios { + input_mode: InputMode::from_bits_truncate(self.c_iflag), + output_mode: OutputMode::from_bits_truncate(self.c_oflag), + control_mode: ControlMode::from_bits_truncate(self.c_cflag), + local_mode: LocalMode::from_bits_truncate(self.c_lflag), + control_characters: self.c_cc.clone(), + line: LineDisciplineType::from_line(self.c_line), + input_speed: self.c_ispeed, + output_speed: self.c_ospeed, + } + } +} + +pub const INIT_CONTORL_CHARACTERS: [u8; CONTORL_CHARACTER_NUM] = [ + b'C' - 0x40, // VINTR + b'\\' - 0x40, // VQUIT + 0o177, // VERASE + b'U' - 0x40, // VKILL + b'D' - 0x40, // VEOF + 1, // VMIN + 0, // VEOL + 0, // VTIME + 0, // VEOL2 + 0, // VSWTC + b'W' - 0x40, // VWERASE + b'R' - 0x40, // VREPRINT + b'Z' - 0x40, // VSUSP + b'Q' - 0x40, // VSTART + b'S' - 0x40, // VSTOP + b'V' - 0x40, // VLNEXT + b'O' - 0x40, // VDISCARD + 0, + 0, +]; + +// pub const INIT_CONTORL_CHARACTERS: [u8; CONTORL_CHARACTER_NUM] = { +// let mut chs: [u8; CONTORL_CHARACTER_NUM] = Default::default(); +// chs[ControlCharIndex::VINTR] = b'C' - 0x40; +// chs[ControlCharIndex::VQUIT] = b'\\' - 0x40; +// chs[ControlCharIndex::VERASE] = 0o177; +// chs[ControlCharIndex::VKILL] = b'U' - 0x40; +// chs[ControlCharIndex::VEOF] = b'D' - 0x40; +// chs[ControlCharIndex::VSTART] = b'Q' - 0x40; +// chs[ControlCharIndex::VSTOP] = b'S' - 0x40; +// chs[ControlCharIndex::VSUSP] = b'Z' - 0x40; +// chs[ControlCharIndex::VREPRINT] = b'R' - 0x40; +// chs[ControlCharIndex::VDISCARD] = b'O' - 0x40; +// chs[ControlCharIndex::VWERASE] = b'W' - 0x40; +// chs[ControlCharIndex::VLNEXT] = b'V' - 0x40; +// // chs[ContorlCharIndex::VDSUSP] = b'Y' - 0x40; +// chs[ControlCharIndex::VMIN] = 1; +// return chs; +// }; + +lazy_static! { + pub static ref TTY_STD_TERMIOS: Termios = { + Termios { + input_mode: InputMode::ICRNL | InputMode::IXON, + output_mode: OutputMode::OPOST | OutputMode::ONLCR, + control_mode: ControlMode::B38400 + | ControlMode::CREAD + | ControlMode::HUPCL + | ControlMode::CS8, + local_mode: LocalMode::ISIG + | LocalMode::ICANON + | LocalMode::ECHO + | LocalMode::ECHOE + | LocalMode::ECHOK + | LocalMode::ECHOCTL + | LocalMode::ECHOKE + | LocalMode::IEXTEN, + control_characters: INIT_CONTORL_CHARACTERS.clone(), + line: LineDisciplineType::NTty, + input_speed: 38400, + output_speed: 38400, + } + }; +} + +pub const CONTORL_CHARACTER_NUM: usize = 19; + +bitflags! { + /// termios输入特性 + pub struct InputMode: u32 { + /// 如果设置了该标志,表示启用软件流控制。 + const IXON = 0x0200; + /// 如果设置了该标志,表示启用输入流控制。 + const IXOFF = 0x0400; + /// Map Uppercase to Lowercase on Input 将大写转换为小写 + /// 表示不区分大小写 + const IUCLC = 0x1000; + /// 如果设置了该标志,表示当输入队列满时,产生一个响铃信号。 + const IMAXBEL = 0x2000; + /// 如果设置了该标志,表示输入数据被视为 UTF-8 编码。 + const IUTF8 = 0x4000; + + /// 忽略中断信号 + const IGNBRK = 0x001; + /// 检测到中断信号时生成中断(产生中断信号) + const BRKINT = 0x002; + /// 忽略具有奇偶校验错误的字符 + const IGNPAR = 0x004; + /// 在检测到奇偶校验错误或帧错误时,将字符以 \377 标记 + const PARMRK = 0x008; + /// 启用输入奇偶校验检查 + const INPCK = 0x010; + /// 从输入字符中剥离第 8 位,即只保留低 7 位 + const ISTRIP = 0x020; + /// 表示将输入的换行符 (\n) 映射为回车符 (\r) + const INLCR = 0x040; + /// 表示忽略回车符 (\r) + const IGNCR = 0x080; + /// 表示将输入的回车符 (\r) 映射为换行符 (\n) + const ICRNL = 0x100; + /// 表示在输入被停止(Ctrl-S)后,任何字符的输入都将重新启动输入 + const IXANY = 0x800; + } + + /// termios输出特性 + pub struct OutputMode: u32 { + /// 在输出时将换行符替换\r\n + const ONLCR = 0x00002; + /// Map Lowercase to Uppercase on Output 输出字符时将小写字母映射为大写字母 + const OLCUC = 0x00004; + + /// 与NL协同 配置换行符的处理方式 + const NLDLY = 0x00300; + const NL0 = 0x00000; // 不延迟换行 + const NL1 = 0x00100; // 延迟换行(输出回车后等待一段时间再输出换行) + const NL2 = 0x00200; // NL2 和 NL3保留,暂未使用 + const NL3 = 0x00300; + + /// 配置水平制表符的处理方式 + const TABDLY = 0x00c00; + const TAB0 = 0x00000; // 不延迟水平制表符 + const TAB1 = 0x00400; // 在输出水平制表符时,延迟到下一个设置的水平制表符位置 + const TAB2 = 0x00800; // 在输出水平制表符时,延迟到下一个设置的 8 的倍数的位置 + const TAB3 = 0x00c00; // TAB3 和 XTABS(与 TAB3 等效)保留,暂未使用 + const XTABS = 0x00c00; + + /// 配置回车符的处理方式 + const CRDLY = 0x03000; + const CR0 = 0x00000; // 不延迟回车 + const CR1 = 0x01000; // 延迟回车(输出回车后等待一段时间再输出换行) + const CR2 = 0x02000; // CR2 和 CR3保留,暂未使用 + const CR3 = 0x03000; + + /// 配置换页符(form feed)的处理方式 + const FFDLY = 0x04000; + const FF0 = 0x00000; // 不延迟换页 + const FF1 = 0x04000; // 延迟换页 + + /// 配置退格符(backspace)的处理方式 + const BSDLY = 0x08000; + const BS0 = 0x00000; // 不延迟退格 + const BS1 = 0x08000; // 延迟退格 + + /// 配置垂直制表符(vertical tab)的处理方式 + const VTDLY = 0x10000; + const VT0 = 0x00000; // 不延迟垂直制表符 + const VT1 = 0x10000; // 延迟垂直制表符 + + /// 表示执行输出处理,即启用输出处理函数 + const OPOST = 0x01; + /// 表示将输出的回车符 (\r) 映射为换行符 (\n) + const OCRNL = 0x08; + /// 表示在输出时,如果光标在第 0 列,则不输出回车符 (\r) + const ONOCR = 0x10; + /// 表示将回车符 (\r) 映射为换行符 (\n) + const ONLRET = 0x20; + /// 表示使用填充字符进行延迟。这个填充字符的默认值是空格。 + const OFILL = 0x40; + /// 表示使用删除字符 (DEL, \177) 作为填充字符 + const OFDEL = 0x80; + } + + /// 配置终端设备的基本特性和控制参数 + pub struct ControlMode: u32 { + /// Baud Rate Mask 指定波特率的掩码 + const CBAUD = 0x000000ff; + /// Extra Baud Bits 指定更高的波特率位 + const CBAUDEX = 0x00000000; + /// Custom Baud Rate 指定自定义波特率 如果设置了 BOTHER,则通过以下位来设置自定义的波特率值 + const BOTHER = 0x0000001f; + + const B0 = 0x00000000; + const B50 = 0x00000001; + const B75 = 0x00000002; + const B110 = 0x00000003; + const B134 = 0x00000004; + const B150 = 0x00000005; + const B200 = 0x00000006; + const B300 = 0x00000007; + const B600 = 0x00000008; + const B1200 = 0x00000009; + const B1800 = 0x0000000a; + const B2400 = 0x0000000b; + const B4800 = 0x0000000c; + const B9600 = 0x0000000d; + const B19200 = 0x0000000e; + const B38400 = 0x0000000f; + + const B57600 = 0x00000010; + const B115200 = 0x00000011; + const B230400 = 0x00000012; + const B460800 = 0x00000013; + const B500000 = 0x00000014; + const B576000 = 0x00000015; + const B921600 = 0x00000016; + const B1000000 = 0x00000017; + const B1152000 = 0x00000018; + const B1500000 = 0x00000019; + const B2000000 = 0x0000001a; + const B2500000 = 0x0000001b; + const B3000000 = 0x0000001c; + const B3500000 = 0x0000001d; + const B4000000 = 0x0000001e; + + /// 指定字符大小的掩码 以下位为特定字符大小 + const CSIZE = 0x00000300; + const CS5 = 0x00000000; + const CS6 = 0x00000100; + const CS7 = 0x00000200; + const CS8 = 0x00000300; + + /// Stop Bit Select 表示使用两个停止位;否则,表示使用一个停止位 + const CSTOPB = 0x00000400; + /// 表示启用接收器。如果未设置,则禁用接收器。 + const CREAD = 0x00000800; + /// 表示启用奇偶校验。如果未设置,则禁用奇偶校验。 + const PARENB = 0x00001000; + /// 表示启用奇校验。如果未设置,则表示启用偶校验。 + const PARODD = 0x00002000; + /// 表示在终端设备被关闭时挂断线路(执行挂断操作) + const HUPCL = 0x00004000; + /// 表示忽略调制解调器的状态(DCD、DSR、CTS 等) + const CLOCAL = 0x00008000; + /// 指定输入波特率的掩码 + const CIBAUD = 0x00ff0000; + + const ADDRB = 0x20000000; + } + + /// 配置终端设备的本地模式(local mode)或控制输入处理的行为 + pub struct LocalMode: u32 { + /// 启用中断字符(Ctrl-C、Ctrl-Z) + const ISIG = 0x00000080; + /// 表示启用规范模式,即启用行缓冲和回显。在规范模式下,输入被缓冲,并且只有在输入回车符时才会传递给应用程序。 + const ICANON = 0x00000100; + /// 表示启用大写模式,即输入输出都将被转换为大写。 + const XCASE = 0x00004000; + /// 表示启用回显(显示用户输入的字符) + const ECHO = 0x00000008; + /// 表示在回显时将擦除的字符用 backspace 和空格字符显示。 + const ECHOE = 0x00000002; + /// 表示在回显时将换行符后的字符用空格字符显示。 + const ECHOK = 0x00000004; + /// 表示在回显时将换行符显示为换行和回车符。 + const ECHONL = 0x00000010; + /// 表示在收到中断(Ctrl-C)和退出(Ctrl-\)字符后,不清空输入和输出缓冲区。 + const NOFLSH = 0x80000000; + /// 表示在后台进程尝试写入终端时,发送停止信号(Ctrl-S) + const TOSTOP = 0x00400000; + /// 表示在回显时,显示控制字符为 ^ 加字符。 + const ECHOCTL= 0x00000040; + /// 表示在回显时显示带有 # 的换行符(为了与 echo -n 命令兼容)。 + const ECHOPRT= 0x00000020; + /// 表示在回显时将 KILL 字符(Ctrl-U)用空格字符显示。 + const ECHOKE = 0x00000001; + /// 表示输出正在被冲刷(flush),通常是由于输入/输出流的状态变化。 + const FLUSHO = 0x00800000; + /// 表示在规范模式下,存在需要重新打印的字符。 + const PENDIN = 0x20000000; + /// 表示启用实现定义的输入处理。 + const IEXTEN = 0x00000400; + /// 表示启用扩展的处理函数 + const EXTPROC= 0x10000000; + } + + pub struct TtySetTermiosOpt: u8 { + const TERMIOS_FLUSH =1; + const TERMIOS_WAIT =2; + const TERMIOS_TERMIO =4; + const TERMIOS_OLD =8; + } +} + +/// 对应termios中控制字符的索引 +pub struct ControlCharIndex; +#[allow(dead_code)] +impl ControlCharIndex { + pub const DISABLE_CHAR: u8 = b'\0'; + /// 中断信号 + pub const VINTR: usize = 0; + /// 退出信号 + pub const VQUIT: usize = 1; + /// 退格 + pub const VERASE: usize = 2; + /// 终止输入信号 + pub const VKILL: usize = 3; + /// 文件结束信号 \0? + pub const VEOF: usize = 4; + /// 指定非规范模式下的最小字符数 + pub const VMIN: usize = 5; + /// 换行符 + pub const VEOL: usize = 6; + /// 指定非规范模式下的超时时间 + pub const VTIME: usize = 7; + /// 换行符 + pub const VEOL2: usize = 8; + /// 未使用,保留 + pub const VSWTC: usize = 9; + /// 擦除前一个单词 + pub const VWERASE: usize = 10; + /// 重新打印整行 + pub const VREPRINT: usize = 11; + /// 挂起信号 + pub const VSUSP: usize = 12; + /// 启动输出信号 + pub const VSTART: usize = 13; + /// 停止输出信号 + pub const VSTOP: usize = 14; + /// 将下一个字符视为字面值,而不是特殊字符 + pub const VLNEXT: usize = 15; + /// 对应于字符丢弃信号,用于丢弃当前输入的行 + pub const VDISCARD: usize = 16; +} diff --git a/kernel/src/driver/tty/tty_core.rs b/kernel/src/driver/tty/tty_core.rs new file mode 100644 index 00000000..f5bd1d2f --- /dev/null +++ b/kernel/src/driver/tty/tty_core.rs @@ -0,0 +1,592 @@ +use core::{fmt::Debug, sync::atomic::AtomicBool}; + +use alloc::{string::String, sync::Arc, vec::Vec}; +use system_error::SystemError; + +use crate::{ + libs::{ + rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + wait_queue::EventWaitQueue, + }, + mm::VirtAddr, + net::event_poll::EPollEventType, + process::Pid, + syscall::user_access::UserBufferWriter, +}; + +use super::{ + termios::{ControlMode, PosixTermios, Termios, TtySetTermiosOpt, WindowSize}, + tty_driver::{TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation}, + tty_ldisc::{ + ntty::{NTtyData, NTtyLinediscipline}, + TtyLineDiscipline, + }, + tty_port::TtyPort, + virtual_terminal::{virtual_console::VirtualConsoleData, VIRT_CONSOLES}, +}; + +#[derive(Debug)] +pub struct TtyCore { + core: TtyCoreData, + /// 线路规程函数集 + line_discipline: Arc, +} + +impl TtyCore { + pub fn new(driver: Arc, index: usize) -> Arc { + let name = driver.tty_line_name(index); + let termios = driver.init_termios(); + let core = TtyCoreData { + tty_driver: driver, + termios: RwLock::new(termios), + name, + flags: RwLock::new(TtyFlag::empty()), + count: RwLock::new(0), + window_size: RwLock::new(WindowSize::default()), + read_wq: EventWaitQueue::new(), + write_wq: EventWaitQueue::new(), + port: RwLock::new(None), + index, + ctrl: SpinLock::new(TtyContorlInfo::default()), + closing: AtomicBool::new(false), + flow: SpinLock::new(TtyFlowState::default()), + }; + + return Arc::new(Self { + core, + line_discipline: Arc::new(NTtyLinediscipline { + data: SpinLock::new(NTtyData::new()), + }), + }); + } + + #[inline] + pub fn core(&self) -> &TtyCoreData { + return &self.core; + } + + #[inline] + pub fn ldisc(&self) -> Arc { + self.line_discipline.clone() + } + + pub fn reopen(&self) -> Result<(), SystemError> { + let tty_core = self.core(); + let driver = tty_core.driver(); + + if driver.tty_driver_type() == TtyDriverType::Pty + && driver.tty_driver_sub_type() == TtyDriverSubType::PtyMaster + { + return Err(SystemError::EIO); + } + + // if *tty_core.count.read() == 0 { + // return Err(SystemError::EAGAIN_OR_EWOULDBLOCK); + // } + + // TODO 判断flags + + tty_core.add_count(); + + Ok(()) + } + + #[inline] + pub fn set_port(&self, port: Arc) { + *self.core.port.write() = Some(port); + } + + pub fn tty_start(&self) { + let mut flow = self.core.flow.lock_irqsave(); + if !flow.stopped || flow.tco_stopped { + return; + } + + flow.stopped = false; + let _ = self.start(self.core()); + self.tty_wakeup(); + } + + pub fn tty_stop(&self) { + let mut flow = self.core.flow.lock_irqsave(); + if flow.stopped { + return; + } + flow.stopped = true; + + let _ = self.stop(self.core()); + } + + pub fn tty_wakeup(&self) { + if self.core.flags.read().contains(TtyFlag::DO_WRITE_WAKEUP) { + let _ = self.ldisc().write_wakeup(self.core()); + } + + self.core() + .write_wq + .wakeup(EPollEventType::EPOLLOUT.bits() as u64); + } + + pub fn tty_mode_ioctl( + &self, + tty: Arc, + cmd: u32, + arg: usize, + ) -> Result { + match cmd { + TtyIoctlCmd::TCGETS => { + let termios = PosixTermios::from_kernel_termios(self.core.termios().clone()); + let mut user_writer = UserBufferWriter::new( + VirtAddr::new(arg).as_ptr::(), + core::mem::size_of::(), + true, + )?; + + user_writer.copy_one_to_user(&termios, 0)?; + return Ok(0); + } + TtyIoctlCmd::TCSETSW => { + return self.core_set_termios( + tty, + VirtAddr::new(arg), + TtySetTermiosOpt::TERMIOS_WAIT | TtySetTermiosOpt::TERMIOS_OLD, + ); + } + _ => { + return Err(SystemError::ENOIOCTLCMD); + } + } + } + + pub fn core_set_termios( + &self, + tty: Arc, + arg: VirtAddr, + opt: TtySetTermiosOpt, + ) -> Result { + let tmp_termios = self.core().termios().clone(); + + if opt.contains(TtySetTermiosOpt::TERMIOS_TERMIO) { + todo!() + } else { + let mut user_writer = UserBufferWriter::new( + arg.as_ptr::(), + core::mem::size_of::(), + true, + )?; + + user_writer.copy_one_to_user(&tmp_termios, 0)?; + } + + if opt.contains(TtySetTermiosOpt::TERMIOS_FLUSH) { + let ld = self.ldisc(); + let _ = ld.flush_buffer(tty.clone()); + } + + if opt.contains(TtySetTermiosOpt::TERMIOS_WAIT) { + // TODO + } + + self.set_termios_next(tty, tmp_termios)?; + Ok(0) + } + + pub fn set_termios_next( + &self, + tty: Arc, + new_termios: Termios, + ) -> Result<(), SystemError> { + let mut termios = self.core().termios_write(); + + let old_termios = termios.clone(); + + *termios = new_termios; + + let tmp = termios.control_mode; + termios.control_mode ^= (tmp ^ old_termios.control_mode) & ControlMode::ADDRB; + + let ret = self.set_termios(tty.clone(), old_termios); + if ret.is_err() { + termios.control_mode &= ControlMode::HUPCL | ControlMode::CREAD | ControlMode::CLOCAL; + termios.control_mode |= old_termios.control_mode + & !(ControlMode::HUPCL | ControlMode::CREAD | ControlMode::CLOCAL); + termios.input_speed = old_termios.input_speed; + termios.output_speed = old_termios.output_speed; + } + + drop(termios); + let ld = self.ldisc(); + ld.set_termios(tty, Some(old_termios))?; + + Ok(()) + } +} + +#[derive(Debug)] +pub struct TtyContorlInfo { + /// 前台进程pid + pub session: Option, + /// 前台进程组id + pub pgid: Option, + + /// packet模式下使用,目前未用到 + pub pktstatus: u8, + pub packet: bool, +} + +impl Default for TtyContorlInfo { + fn default() -> Self { + Self { + session: None, + pgid: None, + pktstatus: Default::default(), + packet: Default::default(), + } + } +} + +#[derive(Debug, Default)] +pub struct TtyCoreWriteData { + /// 写缓冲区 + pub write_buf: Vec, + /// 写入数量 + pub write_cnt: usize, +} + +#[derive(Debug, Default)] +pub struct TtyFlowState { + /// 表示流控是否被停止 + pub stopped: bool, + /// 表示 TCO(Transmit Continuous Operation)流控是否被停止 + pub tco_stopped: bool, +} + +#[derive(Debug)] +pub struct TtyCoreData { + tty_driver: Arc, + termios: RwLock, + name: String, + flags: RwLock, + /// 在初始化时即确定不会更改,所以这里不用加锁 + index: usize, + count: RwLock, + /// 窗口大小 + window_size: RwLock, + /// 读等待队列 + read_wq: EventWaitQueue, + /// 写等待队列 + write_wq: EventWaitQueue, + /// 端口 + port: RwLock>>, + /// 前台进程 + ctrl: SpinLock, + /// 是否正在关闭 + closing: AtomicBool, + /// 流控状态 + flow: SpinLock, +} + +impl TtyCoreData { + #[inline] + pub fn driver(&self) -> Arc { + self.tty_driver.clone() + } + + #[inline] + pub fn flow_irqsave(&self) -> SpinLockGuard { + self.flow.lock_irqsave() + } + + #[inline] + pub fn port(&self) -> Option> { + self.port.read().clone() + } + + #[inline] + pub fn index(&self) -> usize { + self.index + } + + #[inline] + pub fn name(&self) -> String { + self.name.clone() + } + + #[inline] + pub fn flags(&self) -> TtyFlag { + self.flags.read().clone() + } + + #[inline] + pub fn termios(&self) -> RwLockReadGuard<'_, Termios> { + self.termios.read() + } + + #[inline] + pub fn termios_write(&self) -> RwLockWriteGuard { + self.termios.write() + } + + #[inline] + pub fn set_termios(&self, termios: Termios) { + let mut termios_guard = self.termios.write(); + *termios_guard = termios; + } + + #[inline] + pub fn add_count(&self) { + let mut guard = self.count.write(); + *guard += 1; + } + + #[inline] + pub fn read_wq(&self) -> &EventWaitQueue { + &self.read_wq + } + + #[inline] + pub fn write_wq(&self) -> &EventWaitQueue { + &self.write_wq + } + + #[inline] + pub fn contorl_info_irqsave(&self) -> SpinLockGuard { + self.ctrl.lock_irqsave() + } + + #[inline] + pub fn window_size_upgradeable(&self) -> RwLockUpgradableGuard { + self.window_size.upgradeable_read() + } + + #[inline] + pub fn window_size(&self) -> RwLockReadGuard { + self.window_size.read() + } + + #[inline] + pub fn is_closing(&self) -> bool { + self.closing.load(core::sync::atomic::Ordering::SeqCst) + } + + #[inline] + pub fn vc_data_irqsave(&self) -> SpinLockGuard { + VIRT_CONSOLES[self.index].lock_irqsave() + } +} + +/// TTY 核心接口,不同的tty需要各自实现这个trait +pub trait TtyCoreFuncs: Debug + Send + Sync {} + +impl TtyOperation for TtyCore { + #[inline] + fn open(&self, tty: &TtyCoreData) -> Result<(), SystemError> { + return self.core().tty_driver.driver_funcs().open(tty); + } + + #[inline] + fn write_room(&self, tty: &TtyCoreData) -> usize { + return self.core().tty_driver.driver_funcs().write_room(tty); + } + + #[inline] + fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result { + return self.core().tty_driver.driver_funcs().write(tty, buf, nr); + } + + #[inline] + fn flush_chars(&self, tty: &TtyCoreData) { + self.core().tty_driver.driver_funcs().flush_chars(tty); + } + + #[inline] + fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> { + return self.core().tty_driver.driver_funcs().put_char(tty, ch); + } + + #[inline] + fn install(&self, driver: Arc, tty: Arc) -> Result<(), SystemError> { + return self.core().tty_driver.driver_funcs().install(driver, tty); + } + + #[inline] + fn start(&self, tty: &TtyCoreData) -> Result<(), SystemError> { + return self.core().tty_driver.driver_funcs().start(tty); + } + + #[inline] + fn stop(&self, tty: &TtyCoreData) -> Result<(), SystemError> { + return self.core().tty_driver.driver_funcs().stop(tty); + } + + #[inline] + fn ioctl(&self, tty: Arc, cmd: u32, arg: usize) -> Result<(), SystemError> { + return self.core().tty_driver.driver_funcs().ioctl(tty, cmd, arg); + } + + #[inline] + fn chars_in_buffer(&self) -> usize { + return self.core().tty_driver.driver_funcs().chars_in_buffer(); + } + + #[inline] + fn set_termios(&self, tty: Arc, old_termios: Termios) -> Result<(), SystemError> { + return self + .core() + .tty_driver + .driver_funcs() + .set_termios(tty, old_termios); + } +} + +bitflags! { + pub struct TtyFlag: u32 { + /// 终端被节流 + const THROTTLED = 1 << 0; + /// 终端输入输出错误状态 + const IO_ERROR = 1 << 1; + /// 终端的其他一方已关闭 + const OTHER_CLOSED = 1 << 2; + /// 终端处于独占状态 + const EXCLUSIVE = 1 << 3; + /// 终端执行写唤醒操作 + const DO_WRITE_WAKEUP = 1 << 5; + /// 终端线路驱动程序已打开 + const LDISC_OPEN = 1 << 11; + /// 终端伪终端设备已锁定 + const PTY_LOCK = 1 << 16; + /// 终端禁用写分裂操作 + const NO_WRITE_SPLIT = 1 << 17; + /// 终端挂断(挂起)状态 + const HUPPED = 1 << 18; + /// 终端正在挂断(挂起) + const HUPPING = 1 << 19; + /// 终端线路驱动程序正在更改 + const LDISC_CHANGING = 1 << 20; + /// 终端线路驱动程序已停止 + const LDISC_HALTED = 1 << 22; + } +} + +#[derive(Debug, PartialEq)] +pub enum EchoOperation { + /// 开始特殊操作。 + Start, + /// 向后移动光标列。 + MoveBackCol, + /// 设置规范模式下的列位置。 + SetCanonCol, + /// 擦除制表符。 + EraseTab, + + Undefined(u8), +} + +impl EchoOperation { + pub fn from_u8(num: u8) -> EchoOperation { + match num { + 0xff => Self::Start, + 0x80 => Self::MoveBackCol, + 0x81 => Self::SetCanonCol, + 0x82 => Self::EraseTab, + _ => Self::Undefined(num), + } + } + + pub fn to_u8(&self) -> u8 { + match *self { + EchoOperation::Start => 0xff, + EchoOperation::MoveBackCol => 0x80, + EchoOperation::SetCanonCol => 0x81, + EchoOperation::EraseTab => 0x82, + EchoOperation::Undefined(num) => num, + } + } +} + +pub struct TtyIoctlCmd; + +#[allow(dead_code)] +impl TtyIoctlCmd { + /// 获取终端参数 + pub const TCGETS: u32 = 0x5401; + /// 设置终端参数 + pub const TCSETS: u32 = 0x5402; + /// 设置终端参数并等待所有输出完成 + pub const TCSETSW: u32 = 0x5403; + /// 设置终端参数并且等待所有输出完成,但在这之前将终端清空 + pub const TCSETSF: u32 = 0x5404; + /// 获取终端参数 + pub const TCGETA: u32 = 0x5405; + /// 设置终端参数 + pub const TCSETA: u32 = 0x5406; + /// 设置终端参数并等待所有输出完成 + pub const TCSETAW: u32 = 0x5407; + /// 设置终端参数并且等待所有输出完成,但在这之前将终端清空 + pub const TCSETAF: u32 = 0x5408; + /// 发送零字节,等待所有输出完成 + pub const TCSBRK: u32 = 0x5409; + /// 控制终端的流控 + pub const TCXONC: u32 = 0x540A; + /// 刷新输入/输出缓冲区或者丢弃输入缓冲区 + pub const TCFLSH: u32 = 0x540B; + /// 设置设备为独占模式 + pub const TIOCEXCL: u32 = 0x540C; + /// 设置设备为非独占模式 + pub const TIOCNXCL: u32 = 0x540D; + /// 设置当前进程的控制终端 + pub const TIOCSCTTY: u32 = 0x540E; + /// 获取前台进程组 + pub const TIOCGPGRP: u32 = 0x540F; + ///设置前台进程组 + pub const TIOCSPGRP: u32 = 0x5410; + /// 获取输出队列的字节数 + pub const TIOCOUTQ: u32 = 0x5411; + /// 模拟从终端输入字符 + pub const TIOCSTI: u32 = 0x5412; + /// 获取窗口大小 + pub const TIOCGWINSZ: u32 = 0x5413; + /// 设置窗口大小 + pub const TIOCSWINSZ: u32 = 0x5414; + /// 获取终端控制信号的状态 + pub const TIOCMGET: u32 = 0x5415; + /// 设置终端控制信号的位 + pub const TIOCMBIS: u32 = 0x5416; + /// 清除终端控制信号的位 + pub const TIOCMBIC: u32 = 0x5417; + /// 设置终端控制信号的状态 + pub const TIOCMSET: u32 = 0x5418; + /// 获取软件载波状态 + pub const TIOCGSOFTCAR: u32 = 0x5419; + /// 设置软件载波状态 + pub const TIOCSSOFTCAR: u32 = 0x541A; + /// 获取输入队列的字节数 + pub const FIONREAD: u32 = 0x541B; + /// Linux 特有命令 + pub const TIOCLINUX: u32 = 0x541C; + /// 获取控制台设备 + pub const TIOCCONS: u32 = 0x541D; + /// 获取串行设备参数 + pub const TIOCGSERIAL: u32 = 0x541E; + /// 设置串行设备参数 + pub const TIOCSSERIAL: u32 = 0x541F; + /// 设置套接字的报文模式 + pub const TIOCPKT: u32 = 0x5420; + /// 设置非阻塞 I/O + pub const FIONBIO: u32 = 0x5421; + /// 清除控制终端 + pub const TIOCNOTTY: u32 = 0x5422; + /// 设置终端线路驱动器 + pub const TIOCSETD: u32 = 0x5423; + /// 获取终端线路驱动器 + pub const TIOCGETD: u32 = 0x5424; + /// 发送终止条件 + pub const TCSBRKP: u32 = 0x5425; + /// 开始发送零比特 + pub const TIOCSBRK: u32 = 0x5427; + /// 停止发送零比特 + pub const TIOCCBRK: u32 = 0x5428; + /// Return the session ID of FD + pub const TIOCGSID: u32 = 0x5429; +} diff --git a/kernel/src/driver/tty/tty_device.rs b/kernel/src/driver/tty/tty_device.rs index ab1f26de..b6b97c28 100644 --- a/kernel/src/driver/tty/tty_device.rs +++ b/kernel/src/driver/tty/tty_device.rs @@ -1,5 +1,4 @@ use alloc::{ - collections::BTreeMap, string::{String, ToString}, sync::{Arc, Weak}, }; @@ -7,104 +6,318 @@ use system_error::SystemError; use unified_init::macros::unified_init; use crate::{ + arch::ipc::signal::Signal, + driver::{ + base::{ + char::CharDevice, + device::{ + bus::Bus, + device_number::{DeviceNumber, Major}, + device_register, + driver::Driver, + Device, DeviceKObjType, DeviceType, IdTable, + }, + kobject::{KObject, LockedKObjectState}, + kset::KSet, + }, + serial::serial_init, + }, filesystem::{ devfs::{devfs_register, DevFS, DeviceINode}, - vfs::{ - file::FileMode, syscall::ModeType, FilePrivateData, FileType, IndexNode, Metadata, - ROOT_INODE, - }, + kernfs::KernFSInode, + vfs::{file::FileMode, syscall::ModeType, FilePrivateData, FileType, IndexNode, Metadata}, }, init::initcall::INITCALL_DEVICE, - kerror, - libs::{ - lib_ui::textui::{textui_putchar, FontColor}, - rwlock::RwLock, - }, + libs::rwlock::RwLock, + mm::VirtAddr, + process::ProcessManager, + syscall::user_access::UserBufferWriter, }; -use super::{serial::serial_init, TtyCore, TtyError, TtyFileFlag, TtyFilePrivateData}; +use super::{ + termios::WindowSize, + tty_core::{TtyCore, TtyFlag, TtyIoctlCmd}, + tty_driver::{TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation}, + tty_job_control::TtyJobCtrlManager, + virtual_terminal::vty_init, +}; -lazy_static! { - /// 所有TTY设备的B树。用于根据名字,找到Arc - /// TODO: 待设备驱动模型完善,具有类似功能的机制后,删掉这里 - pub static ref TTY_DEVICES: RwLock>> = RwLock::new(BTreeMap::new()); +#[derive(Debug)] +pub struct InnerTtyDevice { + /// 当前设备所述的kset + kset: Option>, + parent_kobj: Option>, + /// 当前设备所述的总线 + bus: Option>, + inode: Option>, + driver: Option>, + can_match: bool, + + metadata: Metadata, +} + +impl InnerTtyDevice { + pub fn new() -> Self { + Self { + kset: None, + parent_kobj: None, + bus: None, + inode: None, + driver: None, + can_match: false, + metadata: Metadata::new(FileType::CharDevice, ModeType::from_bits_truncate(0o755)), + } + } } -/// @brief TTY设备 #[derive(Debug)] +#[cast_to([sync] Device)] pub struct TtyDevice { - /// TTY核心 - core: TtyCore, + name: &'static str, + id_table: IdTable, + inner: RwLock, + kobj_state: LockedKObjectState, /// TTY所属的文件系统 fs: RwLock>, - /// TTY设备私有信息 - private_data: RwLock, -} - -#[derive(Debug)] -struct TtyDevicePrivateData { - /// TTY设备名(如tty1) - name: String, - /// TTY设备文件的元数据 - metadata: Metadata, - // TODO: 增加指向输出端口连接的设备的指针 } impl TtyDevice { - pub fn new(name: &str) -> Arc { - let result = Arc::new(TtyDevice { - core: TtyCore::new(), + pub fn new(name: &'static str, id_table: IdTable) -> Arc { + let dev_num = id_table.device_number(); + let dev = TtyDevice { + name, + id_table, + inner: RwLock::new(InnerTtyDevice::new()), + kobj_state: LockedKObjectState::new(None), fs: RwLock::new(Weak::default()), - private_data: TtyDevicePrivateData::new(name), - }); - // 默认开启输入回显 - result.core.enable_echo(); - return result; - } + }; - /// @brief 判断文件私有信息是否为TTY文件的私有信息 - #[inline] - fn verify_file_private_data<'a>( + dev.inner.write().metadata.raw_dev = dev_num; + + Arc::new(dev) + } +} + +impl IndexNode for TtyDevice { + fn open( &self, - private_data: &'a mut FilePrivateData, - ) -> Result<&'a mut TtyFilePrivateData, SystemError> { - if let FilePrivateData::Tty(t) = private_data { - return Ok(t); - } - return Err(SystemError::EIO); - } + data: &mut crate::filesystem::vfs::FilePrivateData, + mode: &crate::filesystem::vfs::file::FileMode, + ) -> Result<(), SystemError> { + let dev_num = self.metadata()?.raw_dev; - /// @brief 获取TTY设备名 - #[inline] - pub fn name(&self) -> String { - return self.private_data.read().name.clone(); - } + let tty = TtyDriver::open_tty(dev_num)?; - /// @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(()); - } + // 设置privdata + *data = FilePrivateData::Tty(TtyFilePrivateData { + tty: tty.clone(), + mode: *mode, + }); - /// @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 ret = tty.open(tty.core()); + if ret.is_err() { + let err = ret.unwrap_err(); + if err == SystemError::ENOSYS { + return Err(SystemError::ENODEV); + } + return Err(err); } - 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); + let driver = tty.core().driver(); + // 考虑noctty(当前tty) + if !(mode.contains(FileMode::O_NOCTTY) && dev_num == DeviceNumber::new(Major::TTY_MAJOR, 0) + || dev_num == DeviceNumber::new(Major::TTYAUX_MAJOR, 1) + || (driver.tty_driver_type() == TtyDriverType::Pty + && driver.tty_driver_sub_type() == TtyDriverSubType::PtyMaster)) + { + let pcb = ProcessManager::current_pcb(); + let pcb_tty = pcb.sig_info().tty(); + if pcb_tty.is_none() && tty.core().contorl_info_irqsave().session.is_none() { + TtyJobCtrlManager::proc_set_tty(tty); } } + + Ok(()) + } + + fn read_at( + &self, + _offset: usize, + len: usize, + buf: &mut [u8], + data: &mut crate::filesystem::vfs::FilePrivateData, + ) -> Result { + let (tty, mode) = if let FilePrivateData::Tty(tty_priv) = data { + (tty_priv.tty.clone(), tty_priv.mode) + } else { + return Err(SystemError::EIO); + }; + + let ld = tty.ldisc(); + let mut offset = 0; + let mut cookie = false; + loop { + let mut size = if len > buf.len() { buf.len() } else { len }; + size = ld.read(tty.clone(), buf, size, &mut cookie, offset, mode)?; + // 没有更多数据 + if size == 0 { + break; + } + + offset += size; + + // 缓冲区写满 + if offset >= len { + break; + } + + // 没有更多数据 + if !cookie { + break; + } + } + + return Ok(offset); + } + + fn write_at( + &self, + _offset: usize, + len: usize, + buf: &[u8], + data: &mut crate::filesystem::vfs::FilePrivateData, + ) -> Result { + let mut count = len; + let (tty, mode) = if let FilePrivateData::Tty(tty_priv) = data { + (tty_priv.tty.clone(), tty_priv.mode) + } else { + return Err(SystemError::EIO); + }; + + let ld = tty.ldisc(); + let core = tty.core(); + let mut chunk = 2048; + if core.flags().contains(TtyFlag::NO_WRITE_SPLIT) { + chunk = 65536; + } + chunk = chunk.min(count); + + let pcb = ProcessManager::current_pcb(); + let mut written = 0; + loop { + // 至少需要写多少 + let size = chunk.min(count); + + // 将数据从buf拷贝到writebuf + + let ret = ld.write(tty.clone(), buf, size, mode)?; + + written += ret; + count -= ret; + + if count == 0 { + break; + } + + if pcb.sig_info().sig_pending().has_pending() { + return Err(SystemError::ERESTARTSYS); + } + } + + if written > 0 { + // todo: 更新时间 + } + + Ok(written) + } + + fn fs(&self) -> Arc { + todo!() + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + todo!() + } + + fn list(&self) -> Result, system_error::SystemError> { + todo!() + } + + fn metadata(&self) -> Result { + Ok(self.inner.read().metadata.clone()) + } + + fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> { + Ok(()) + } + + fn resize(&self, _len: usize) -> Result<(), SystemError> { + Ok(()) + } + + fn ioctl(&self, cmd: u32, arg: usize, data: &FilePrivateData) -> Result { + let (tty, _) = if let FilePrivateData::Tty(tty_priv) = data { + (tty_priv.tty.clone(), tty_priv.mode) + } else { + return Err(SystemError::EIO); + }; + + match cmd { + TtyIoctlCmd::TIOCSETD + | TtyIoctlCmd::TIOCSBRK + | TtyIoctlCmd::TIOCCBRK + | TtyIoctlCmd::TCSBRK + | TtyIoctlCmd::TCSBRKP => { + TtyJobCtrlManager::tty_check_change(tty.clone(), Signal::SIGTTOU)?; + if cmd != TtyIoctlCmd::TIOCCBRK { + todo!() + } + } + _ => {} + } + + match cmd { + TtyIoctlCmd::TIOCGWINSZ => { + let core = tty.core(); + let winsize = *core.window_size(); + + let mut user_writer = UserBufferWriter::new( + VirtAddr::new(arg).as_ptr::(), + core::mem::size_of::(), + true, + )?; + + let err = user_writer.copy_one_to_user(&winsize, 0); + if err.is_err() { + return Err(SystemError::EFAULT); + } + return Ok(0); + } + _ => match TtyJobCtrlManager::job_ctrl_ioctl(tty.clone(), cmd, arg) { + Ok(_) => { + return Ok(0); + } + Err(e) => { + if e != SystemError::ENOIOCTLCMD { + return Err(e); + } + } + }, + } + + match tty.ioctl(tty.clone(), cmd, arg) { + Ok(_) => { + return Ok(0); + } + Err(e) => { + if e != SystemError::ENOIOCTLCMD { + return Err(e); + } + } + } + tty.ldisc().ioctl(tty, cmd, arg)?; + + Ok(0) } } @@ -114,219 +327,181 @@ 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 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, - len: usize, - buf: &mut [u8], - data: &mut crate::filesystem::vfs::FilePrivateData, - ) -> Result { - let _data: &mut TtyFilePrivateData = match self.verify_file_private_data(data) { - Ok(t) => t, - Err(e) => { - kerror!("Try to read tty device, but file private data type mismatch!"); - return Err(e); - } - }; - self.check_rw_param(len, buf)?; - - // 读取stdin队列 - let r: Result = self.core.read_stdin(&mut buf[0..len], true); - if r.is_ok() { - return Ok(r.unwrap()); - } - - match r.unwrap_err() { - TtyError::EOF(n) => { - return Ok(n); - } - - x => { - kerror!("Error occurred when reading tty, msg={x:?}"); - return Err(SystemError::ECONNABORTED); - } - } - } - - fn write_at( - &self, - _offset: usize, - len: usize, - buf: &[u8], - data: &mut crate::filesystem::vfs::FilePrivateData, - ) -> Result { - let data: &mut TtyFilePrivateData = match self.verify_file_private_data(data) { - Ok(t) => t, - Err(e) => { - kerror!("Try to write tty device, but file private data type mismatch!"); - return Err(e); - } - }; - - self.check_rw_param(len, buf)?; - - let mut cnt: usize = 0; - // 根据当前文件是stdout还是stderr,选择不同的发送方式 - let r: Result = if data.flags.contains(TtyFileFlag::STDOUT) { - loop { - let r = self.core.stdout(&buf[cnt..len], false); - if let Err(TtyError::BufferFull(c)) = r { - self.sync().expect("Failed to sync tty device!"); - cnt += c; - } else { - break r; - } - } - } else if data.flags.contains(TtyFileFlag::STDERR) { - loop { - let r = self.core.stderr(&buf[cnt..len], false); - if let Err(TtyError::BufferFull(c)) = r { - self.sync().expect("Failed to sync tty device!"); - cnt += c; - } else { - break r; - } - } - } else { - return Err(SystemError::EPERM); - }; - - if r.is_ok() { - self.sync().expect("Failed to sync tty device!"); - return Ok(cnt + r.unwrap()); - } - - let r: TtyError = r.unwrap_err(); - kerror!("Error occurred when writing tty deivce. Error msg={r:?}"); - return Err(SystemError::EIO); - } - - fn fs(&self) -> Arc { - return self.fs.read().upgrade().unwrap(); - } - +impl KObject for TtyDevice { fn as_any_ref(&self) -> &dyn core::any::Any { self } - fn list(&self) -> Result, SystemError> { - return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + fn set_inode(&self, inode: Option>) { + self.inner.write().inode = inode; } - fn metadata(&self) -> Result { - return Ok(self.private_data.read().metadata.clone()); + fn inode(&self) -> Option> { + self.inner.read().inode.clone() } - fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> { - return Ok(()); + fn parent(&self) -> Option> { + self.inner.read().parent_kobj.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner.write().parent_kobj = parent + } + + fn kset(&self) -> Option> { + self.inner.read().kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner.write().kset = kset + } + + fn kobj_type(&self) -> Option<&'static dyn crate::driver::base::kobject::KObjType> { + Some(&DeviceKObjType) + } + + fn set_kobj_type(&self, _ktype: Option<&'static dyn crate::driver::base::kobject::KObjType>) {} + + fn name(&self) -> alloc::string::String { + self.name.to_string() + } + + fn set_name(&self, _name: alloc::string::String) { + // self.name = name + } + + fn kobj_state( + &self, + ) -> crate::libs::rwlock::RwLockReadGuard { + self.kobj_state.read() + } + + fn kobj_state_mut( + &self, + ) -> crate::libs::rwlock::RwLockWriteGuard { + self.kobj_state.write() + } + + fn set_kobj_state(&self, state: crate::driver::base::kobject::KObjectState) { + *self.kobj_state.write() = state + } +} + +impl Device for TtyDevice { + fn dev_type(&self) -> crate::driver::base::device::DeviceType { + DeviceType::Char + } + + fn id_table(&self) -> crate::driver::base::device::IdTable { + self.id_table.clone() + } + + fn set_bus(&self, bus: Option>) { + self.inner.write().bus = bus + } + + fn set_class(&self, _class: Option>) { + todo!() + } + + fn driver(&self) -> Option> { + self.inner.read().driver.clone()?.upgrade() + } + + fn set_driver( + &self, + driver: Option>, + ) { + self.inner.write().driver = driver + } + + fn is_dead(&self) -> bool { + false + } + + fn can_match(&self) -> bool { + self.inner.read().can_match + } + + fn set_can_match(&self, can_match: bool) { + self.inner.write().can_match = can_match + } + + fn state_synced(&self) -> bool { + true + } +} + +impl CharDevice for TtyDevice { + fn read(&self, _len: usize, _buf: &mut [u8]) -> Result { + todo!() + } + + fn write(&self, _len: usize, _buf: &[u8]) -> Result { + todo!() } fn sync(&self) -> Result<(), SystemError> { - // TODO: 引入IO重定向后,需要将输出重定向到对应的设备。 - // 目前只是简单的输出到屏幕(为了实现的简便) - - loop { - let mut buf = [0u8; 512]; - let r: Result = self.core.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; - } - // 输出到屏幕 - - for x in 0..len { - textui_putchar(buf[x] as char, FontColor::WHITE, FontColor::BLACK).ok(); - } - } - return Ok(()); - } - fn resize(&self, _len: usize) -> Result<(), SystemError> { - return Ok(()); + todo!() } } -impl TtyDevicePrivateData { - pub fn new(name: &str) -> RwLock { - let mut metadata = Metadata::new(FileType::CharDevice, ModeType::from_bits_truncate(0o755)); - metadata.size = TtyCore::STDIN_BUF_SIZE as i64; - return RwLock::new(TtyDevicePrivateData { - name: name.to_string(), - metadata, - }); - } +#[derive(Debug, Clone)] +pub struct TtyFilePrivateData { + tty: Arc, + mode: FileMode, } -/// @brief 初始化TTY设备 +/// 初始化tty设备和console子设备 #[unified_init(INITCALL_DEVICE)] +#[inline(never)] 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(); + let tty = TtyDevice::new( + "tty0", + IdTable::new( + String::from("tty0"), + Some(DeviceNumber::new(Major::TTY_MAJOR, 0)), + ), + ); - // 如果已经存在了这个设备 - if guard.contains_key("tty0") { - return Err(SystemError::EEXIST); - } + let console = TtyDevice::new( + "console", + IdTable::new( + String::from("console"), + Some(DeviceNumber::new(Major::TTYAUX_MAJOR, 1)), + ), + ); - let mut guard = guard.upgrade(); + // 注册tty设备 + // CharDevOps::cdev_add( + // tty.clone() as Arc, + // IdTable::new( + // String::from("tty0"), + // Some(DeviceNumber::new(Major::TTYAUX_MAJOR, 0)), + // ), + // 1, + // )?; - guard.insert("tty0".to_string(), tty.clone()); + // CharDevOps::register_chardev_region(DeviceNumber::new(Major::TTYAUX_MAJOR, 0), 1, "/dev/tty")?; - drop(guard); + // 注册console设备 + // CharDevOps::cdev_add( + // console.clone() as Arc, + // IdTable::new( + // String::from("console"), + // Some(DeviceNumber::new(Major::TTYAUX_MAJOR, 1)), + // ), + // 1, + // )?; - let r = devfs_register(&tty.name(), tty); - if r.is_err() { - return Err(devfs_root_inode.unwrap_err()); - } + // CharDevOps::register_chardev_region(DeviceNumber::new(Major::TTYAUX_MAJOR, 1), 1, "/dev/tty")?; + + // 将这两个设备注册到devfs,TODO:这里console设备应该与tty在一个设备group里面 + device_register(tty.clone())?; + device_register(console.clone())?; + devfs_register(tty.name, tty)?; + devfs_register(console.name, console)?; serial_init()?; - return Ok(()); + return vty_init(); } diff --git a/kernel/src/driver/tty/tty_driver.rs b/kernel/src/driver/tty/tty_driver.rs index f3715ddb..4b22f653 100644 --- a/kernel/src/driver/tty/tty_driver.rs +++ b/kernel/src/driver/tty/tty_driver.rs @@ -1,61 +1,446 @@ -use core::fmt::Debug; +use core::{fmt::Debug, sync::atomic::Ordering}; -use alloc::sync::Arc; +use alloc::{string::String, sync::Arc, vec::Vec}; +use hashbrown::HashMap; +use system_error::SystemError; -use crate::driver::base::device::driver::Driver; +use crate::{ + driver::{ + base::{ + char::CharDevOps, + device::{ + device_number::{DeviceNumber, Major}, + driver::Driver, + }, + kobject::KObject, + }, + tty::tty_port::TtyPortState, + }, + libs::spinlock::SpinLock, +}; -use super::tty_device::TtyDevice; +use super::{ + termios::Termios, + tty_core::{TtyCore, TtyCoreData}, + tty_ldisc::TtyLdiscManager, + tty_port::TTY_PORTS, + virtual_terminal::virtual_console::CURRENT_VCNUM, +}; -/// TTY 驱动 -/// -/// -/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/tty_driver.h#434 -pub trait TtyDriver: Debug + Send + Sync + Driver { - fn driver_name(&self) -> &str; - fn dev_name(&self) -> &str; +lazy_static! { + static ref TTY_DRIVERS: SpinLock>> = SpinLock::new(Vec::new()); +} - fn metadata(&self) -> &TtyDriverMetadata; +pub struct TtyDriverManager; +impl TtyDriverManager { + pub fn lookup_tty_driver(dev_num: DeviceNumber) -> Option<(usize, Arc)> { + let drivers_guard = TTY_DRIVERS.lock(); + for (index, driver) in drivers_guard.iter().enumerate() { + let base = DeviceNumber::new(driver.major, driver.minor_start); + if dev_num < base || dev_num.data() > base.data() + driver.device_count { + continue; + } + return Some((index, driver.clone())); + } - fn other(&self) -> Option<&Arc>; - - fn ttys(&self) -> &[Arc]; - - fn tty_ops(&self) -> Option<&'static dyn TtyDriverOperations> { None } -} -#[derive(Debug, Clone, Copy)] -#[allow(dead_code)] -pub struct TtyDriverMetadata { - /// name of the driver used in /proc/tty - driver_name: &'static str, - /// used for constructing /dev node name - dev_name: &'static str, - /// used as a number base for constructing /dev node name - name_base: i32, - /// major /dev device number (zero for autoassignment) - major: i32, - /// the first minor /dev device number - minor_start: i32, - drv_type: TtyDriverType, - subtype: TtyDriverSubtype, -} + /// ## 注册驱动 + pub fn tty_register_driver(mut driver: TtyDriver) -> Result<(), SystemError> { + // 查看是否注册设备号 + if driver.major == Major::UNNAMED_MAJOR { + let dev_num = CharDevOps::alloc_chardev_region( + driver.minor_start, + driver.device_count, + driver.name, + )?; + driver.major = dev_num.major(); + driver.minor_start = dev_num.minor(); + } else { + let dev_num = DeviceNumber::new(driver.major, driver.minor_start); + CharDevOps::register_chardev_region(dev_num, driver.device_count, driver.name)?; + } -/// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/tty_driver.h#411 -#[derive(Debug, Clone, Copy)] -pub enum TtyDriverType {} + driver.flags |= TtyDriverFlag::TTY_DRIVER_INSTALLED; -/// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/tty_driver.h#412 -#[derive(Debug, Clone, Copy)] -pub enum TtyDriverSubtype {} + // 加入全局TtyDriver表 + TTY_DRIVERS.lock().push(Arc::new(driver)); -bitflags! { - /// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/tty_driver.h?fi=SERIAL_TYPE_NORMAL#492 - pub struct TtyDriverFlags: u64 { + // TODO: 加入procfs? + Ok(()) } } -/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/tty_driver.h#350 -pub trait TtyDriverOperations {} +#[allow(dead_code)] +#[derive(Debug)] +#[cast_to([sync] Driver)] +pub struct TtyDriver { + /// /proc/tty中使用的驱动程序名称 + driver_name: String, + /// 用于构造/dev节点名称,例如name设置为tty,则按照name_base分配节点tty0,tty1等 + name: &'static str, + /// 命名基数 + name_base: usize, + /// 主设备号 + major: Major, + /// 起始次设备号 + minor_start: u32, + /// 最多支持的tty数量 + device_count: u32, + /// tty驱动程序类型 + tty_driver_type: TtyDriverType, + /// 驱动程序子类型 + tty_driver_sub_type: TtyDriverSubType, + /// 每个tty的默认termios + init_termios: Termios, + /// 懒加载termios,在tty设备关闭时,会将termios按照设备的index保存进这个集合,以便下次打开使用 + saved_termios: Vec, + /// 驱动程序标志 + flags: TtyDriverFlag, + /// pty链接此driver的入口 + pty: Option>, + /// 具体类型的tty驱动方法 + driver_funcs: Arc, + /// 管理的tty设备列表 + ttys: SpinLock>>, + // procfs入口? +} + +impl TtyDriver { + pub fn new( + count: u32, + node_name: &'static str, + node_name_base: usize, + major: Major, + minor_start: u32, + tty_driver_type: TtyDriverType, + default_termios: Termios, + driver_funcs: Arc, + ) -> Self { + TtyDriver { + driver_name: Default::default(), + name: node_name, + name_base: node_name_base, + major, + minor_start, + device_count: count, + tty_driver_type, + tty_driver_sub_type: Default::default(), + init_termios: default_termios, + flags: TtyDriverFlag::empty(), + pty: Default::default(), + driver_funcs, + ttys: SpinLock::new(HashMap::new()), + saved_termios: Vec::with_capacity(count as usize), + } + } + + pub fn tty_line_name(&self, index: usize) -> String { + if self + .flags + .contains(TtyDriverFlag::TTY_DRIVER_UNNUMBERED_NODE) + { + return format!("{}", self.name); + } else { + return format!("{}{}", self.name, index + self.name_base); + } + } + + pub fn add_tty(&self, tty_core: Arc) { + self.ttys.lock().insert(tty_core.core().index(), tty_core); + } + + #[inline] + pub fn driver_funcs(&self) -> Arc { + self.driver_funcs.clone() + } + + #[inline] + pub fn flags(&self) -> TtyDriverFlag { + self.flags + } + + #[inline] + fn lockup_tty(&self, index: usize) -> Option> { + let device_guard = self.ttys.lock(); + return match device_guard.get(&index) { + Some(tty) => Some(tty.clone()), + None => None, + }; + } + + fn standard_install(&self, tty_core: Arc) -> Result<(), SystemError> { + let tty = tty_core.core(); + let tty_index = tty.index(); + // 初始化termios + if !self.flags.contains(TtyDriverFlag::TTY_DRIVER_RESET_TERMIOS) { + // 先查看是否有已经保存的termios + if let Some(t) = self.saved_termios.get(tty_index) { + let mut termios = t.clone(); + termios.line = self.init_termios.line; + tty.set_termios(termios); + } + } + // TODO:设置termios波特率? + + tty.add_count(); + + self.ttys.lock().insert(tty_index, tty_core); + + Ok(()) + } + + fn driver_install_tty(driver: Arc, tty: Arc) -> Result<(), SystemError> { + let res = tty.install(driver.clone(), tty.clone()); + + if res.is_err() { + let err = res.unwrap_err(); + if err == SystemError::ENOSYS { + return driver.standard_install(tty); + } else { + return Err(err); + } + } + + driver.add_tty(tty); + + Ok(()) + } + + fn init_tty_device(driver: Arc, index: usize) -> Result, SystemError> { + let tty = TtyCore::new(driver.clone(), index); + + Self::driver_install_tty(driver.clone(), tty.clone())?; + + let core = tty.core(); + + if core.port().is_none() { + TTY_PORTS[core.index()].setup_tty(Arc::downgrade(&tty)); + tty.set_port(TTY_PORTS[core.index()].clone()); + } + + TtyLdiscManager::ldisc_setup(tty.clone(), None)?; + + Ok(tty) + } + + /// ## 通过设备号找到对应驱动并且初始化Tty + pub fn open_tty(dev_num: DeviceNumber) -> Result, SystemError> { + let (index, driver) = + TtyDriverManager::lookup_tty_driver(dev_num).ok_or(SystemError::ENODEV)?; + + let tty = match driver.lockup_tty(index) { + Some(tty) => { + // TODO: 暂时这么写,因为还没写TtyPort + if tty.core().port().is_none() { + kwarn!("{} port is None", tty.core().name()); + } else { + if tty.core().port().unwrap().state() == TtyPortState::KOPENED { + return Err(SystemError::EBUSY); + } + } + + tty.reopen()?; + tty + } + None => Self::init_tty_device(driver, index)?, + }; + + CURRENT_VCNUM.store(index as isize, Ordering::SeqCst); + + return Ok(tty); + } + + pub fn tty_driver_type(&self) -> TtyDriverType { + self.tty_driver_type + } + + pub fn tty_driver_sub_type(&self) -> TtyDriverSubType { + self.tty_driver_sub_type + } + + pub fn init_termios(&self) -> Termios { + self.init_termios + } +} + +impl KObject for TtyDriver { + fn as_any_ref(&self) -> &dyn core::any::Any { + todo!() + } + + fn set_inode(&self, _inode: Option>) { + todo!() + } + + fn inode(&self) -> Option> { + todo!() + } + + fn parent(&self) -> Option> { + todo!() + } + + fn set_parent(&self, _parent: Option>) { + todo!() + } + + fn kset(&self) -> Option> { + todo!() + } + + fn set_kset(&self, _kset: Option>) { + todo!() + } + + fn kobj_type(&self) -> Option<&'static dyn crate::driver::base::kobject::KObjType> { + todo!() + } + + fn set_kobj_type(&self, _ktype: Option<&'static dyn crate::driver::base::kobject::KObjType>) { + todo!() + } + + fn name(&self) -> alloc::string::String { + todo!() + } + + fn set_name(&self, _name: alloc::string::String) { + todo!() + } + + fn kobj_state( + &self, + ) -> crate::libs::rwlock::RwLockReadGuard { + todo!() + } + + fn kobj_state_mut( + &self, + ) -> crate::libs::rwlock::RwLockWriteGuard { + todo!() + } + + fn set_kobj_state(&self, _state: crate::driver::base::kobject::KObjectState) { + todo!() + } +} + +impl Driver for TtyDriver { + fn id_table(&self) -> Option { + todo!() + } + + fn devices( + &self, + ) -> alloc::vec::Vec> { + todo!() + } + + fn add_device(&self, _device: alloc::sync::Arc) { + todo!() + } + + fn delete_device(&self, _device: &alloc::sync::Arc) { + todo!() + } + + fn set_bus(&self, _bus: Option>) { + todo!() + } +} + +pub trait TtyOperation: Sync + Send + Debug { + fn install(&self, _driver: Arc, _tty: Arc) -> Result<(), SystemError> { + return Err(SystemError::ENOSYS); + } + + fn open(&self, tty: &TtyCoreData) -> Result<(), SystemError>; + + /// ## 获取可写字符数 + fn write_room(&self, _tty: &TtyCoreData) -> usize { + // 默认 + 2048 + } + + fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result; + + fn flush_chars(&self, tty: &TtyCoreData); + + fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError>; + + fn start(&self, _tty: &TtyCoreData) -> Result<(), SystemError> { + Err(SystemError::ENOSYS) + } + + fn stop(&self, _tty: &TtyCoreData) -> Result<(), SystemError> { + Err(SystemError::ENOSYS) + } + + fn flush_buffer(&self, _tty: &TtyCoreData) -> Result<(), SystemError> { + Err(SystemError::ENOSYS) + } + + fn ioctl(&self, tty: Arc, cmd: u32, arg: usize) -> Result<(), SystemError>; + + fn chars_in_buffer(&self) -> usize { + 0 + } + + fn set_termios(&self, _tty: Arc, _old_termios: Termios) -> Result<(), SystemError> { + Err(SystemError::ENOSYS) + } +} + +#[allow(dead_code)] +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum TtyDriverType { + System, + Console, + Serial, + Pty, + Scc, + Syscons, +} + +#[allow(dead_code)] +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum TtyDriverSubType { + Undefined, + Tty, + Console, + Syscons, + Sysptmx, + PtyMaster, + PtySlave, + SerialNormal, +} + +impl Default for TtyDriverSubType { + fn default() -> Self { + Self::Undefined + } +} + +bitflags! { + pub struct TtyDriverFlag: u32 { + /// 表示 tty 驱动程序已安装 + const TTY_DRIVER_INSTALLED = 0x0001; + /// 请求 tty 层在最后一个进程关闭设备时重置 termios 设置 + const TTY_DRIVER_RESET_TERMIOS = 0x0002; + /// 表示驱动程序将保证在设置了该标志的 tty 上不设置任何特殊字符处理标志(原模式) + const TTY_DRIVER_REAL_RAW = 0x0004; + + /// 以下四个标志位为内存分配相关,目前设计无需使用 + const TTY_DRIVER_DYNAMIC_DEV = 0x0008; + const TTY_DRIVER_DEVPTS_MEM = 0x0010; + const TTY_DRIVER_HARDWARE_BREAK = 0x0020; + const TTY_DRIVER_DYNAMIC_ALLOC = 0x0040; + + /// 表示不创建带有编号的 /dev 节点。 + /// 例如,创建 /dev/ttyprintk 而不是 /dev/ttyprintk0。仅在为单个 tty 设备分配驱动程序时适用。 + const TTY_DRIVER_UNNUMBERED_NODE = 0x0080; + } +} diff --git a/kernel/src/driver/tty/tty_job_control.rs b/kernel/src/driver/tty/tty_job_control.rs new file mode 100644 index 00000000..9387ea23 --- /dev/null +++ b/kernel/src/driver/tty/tty_job_control.rs @@ -0,0 +1,139 @@ +use alloc::sync::Arc; +use system_error::SystemError; + +use crate::{ + arch::ipc::signal::{SigSet, Signal}, + mm::VirtAddr, + process::{Pid, ProcessManager}, + syscall::{user_access::UserBufferWriter, Syscall}, +}; + +use super::tty_core::{TtyCore, TtyIoctlCmd}; + +pub struct TtyJobCtrlManager; + +impl TtyJobCtrlManager { + /// ### 设置当前进程的tty + pub fn proc_set_tty(tty: Arc) { + let core = tty.core(); + let mut ctrl = core.contorl_info_irqsave(); + let pcb = ProcessManager::current_pcb(); + + // todo 目前将pgid设置为pid + ctrl.pgid = Some(pcb.pid()); + ctrl.session = Some(pcb.pid()); + + assert!(pcb.sig_info_irqsave().tty().is_none()); + + let mut singal = pcb.sig_info_mut(); + drop(ctrl); + singal.set_tty(tty); + } + + /// ### 检查tty + pub fn tty_check_change(tty: Arc, sig: Signal) -> Result<(), SystemError> { + let pcb = ProcessManager::current_pcb(); + + if pcb.sig_info().tty().is_none() || !Arc::ptr_eq(&pcb.sig_info().tty().unwrap(), &tty) { + return Ok(()); + } + + let core = tty.core(); + let ctrl = core.contorl_info_irqsave(); + + // todo pgid + let pgid = pcb.pid(); + let tty_pgid = ctrl.pgid; + + if tty_pgid.is_some() && tty_pgid.unwrap() != pgid { + if pcb + .sig_info_irqsave() + .sig_block() + .contains(SigSet::from_bits_truncate(1 << sig as u64)) + || pcb.sig_struct_irqsave().handlers[sig as usize].is_ignore() + { + // 忽略该信号 + if sig == Signal::SIGTTIN { + return Err(SystemError::EIO); + } + } else { + // 暂时使用kill而不是killpg + Syscall::kill(pgid, sig as i32)?; + return Err(SystemError::ERESTART); + } + } + + Ok(()) + } + + pub fn job_ctrl_ioctl(tty: Arc, cmd: u32, arg: usize) -> Result { + match cmd { + TtyIoctlCmd::TIOCSPGRP => { + match Self::tty_check_change(tty.clone(), Signal::SIGTTOU) { + Ok(_) => {} + Err(e) => { + if e == SystemError::EIO { + return Err(SystemError::ENOTTY); + } + return Err(e); + } + }; + + // let user_reader = UserBufferReader::new( + // VirtAddr::new(arg).as_ptr::(), + // core::mem::size_of::(), + // true, + // )?; + + // let pgrp = user_reader.read_one_from_user::(0)?; + + let current = ProcessManager::current_pcb(); + + let mut ctrl = tty.core().contorl_info_irqsave(); + + if current.sig_info().tty().is_none() + || !Arc::ptr_eq(¤t.sig_info().tty().clone().unwrap(), &tty) + || ctrl.session.is_none() + || ctrl.session.unwrap() != current.pid() + { + return Err(SystemError::ENOTTY); + } + + ctrl.pgid = Some(Pid::new(arg)); + + return Ok(0); + } + + TtyIoctlCmd::TIOCGPGRP => { + let current = ProcessManager::current_pcb(); + if current.sig_info().tty().is_some() + && !Arc::ptr_eq(¤t.sig_info().tty().unwrap(), &tty) + { + return Err(SystemError::ENOTTY); + } + + let mut user_writer = UserBufferWriter::new( + VirtAddr::new(arg).as_ptr::(), + core::mem::size_of::(), + true, + )?; + + user_writer.copy_one_to_user( + &(tty + .core() + .contorl_info_irqsave() + .pgid + .unwrap_or(Pid::new(0)) + .data() as i32), + 0, + )?; + + return Ok(0); + } + + _ => { + return Err(SystemError::ENOIOCTLCMD); + } + } + } +} diff --git a/kernel/src/driver/tty/tty_ldisc/mod.rs b/kernel/src/driver/tty/tty_ldisc/mod.rs new file mode 100644 index 00000000..722a0d61 --- /dev/null +++ b/kernel/src/driver/tty/tty_ldisc/mod.rs @@ -0,0 +1,117 @@ +use core::fmt::Debug; + +use alloc::sync::Arc; +use system_error::SystemError; + +use crate::filesystem::vfs::file::FileMode; + +use super::{ + termios::Termios, + tty_core::{TtyCore, TtyCoreData}, +}; + +pub mod ntty; + +pub trait TtyLineDiscipline: Sync + Send + Debug { + fn open(&self, tty: Arc) -> Result<(), SystemError>; + fn close(&self, tty: Arc) -> Result<(), SystemError>; + fn flush_buffer(&self, tty: Arc) -> Result<(), SystemError>; + + /// ## tty行规程循环读取函数 + /// + /// ### 参数 + /// - tty: 操作的tty + /// - buf: 数据将被读取到buf + /// - len: 读取的字节长度 + /// - cookie: 表示是否是继续上次的读,第一次读取应该传入false + /// - offset: 读取的偏移量 + fn read( + &self, + tty: Arc, + buf: &mut [u8], + len: usize, + cookie: &mut bool, + offset: usize, + mode: FileMode, + ) -> Result; + fn write( + &self, + tty: Arc, + buf: &[u8], + len: usize, + mode: FileMode, + ) -> Result; + fn ioctl(&self, tty: Arc, cmd: u32, arg: usize) -> Result; + + /// ### 设置termios后更新行规程状态 + /// + /// - old: 之前的termios,如果为None则表示第一次设置 + fn set_termios(&self, tty: Arc, old: Option) -> Result<(), SystemError>; + + fn poll(&self, tty: Arc) -> Result<(), SystemError>; + fn hangup(&self, tty: Arc) -> Result<(), SystemError>; + + /// ## 接收数据 + fn receive_buf( + &self, + tty: Arc, + buf: &[u8], + flags: Option<&[u8]>, + count: usize, + ) -> Result; + + /// ## 接收数据 + fn receive_buf2( + &self, + tty: Arc, + buf: &[u8], + flags: Option<&[u8]>, + count: usize, + ) -> Result; + + /// ## 唤醒线路写者 + fn write_wakeup(&self, _tty: &TtyCoreData) -> Result<(), SystemError> { + Err(SystemError::ENOSYS) + } +} + +#[derive(Debug, Clone, Copy)] +pub enum LineDisciplineType { + NTty = 0, +} + +impl LineDisciplineType { + pub fn from_line(line: u8) -> Self { + match line { + 0 => Self::NTty, + _ => { + todo!() + } + } + } +} + +pub struct TtyLdiscManager; + +impl TtyLdiscManager { + /// ## 为tty初始化ldisc + /// + /// ### 参数 + /// - tty:需要设置的tty + /// - o_tty: other tty 用于pty pair + pub fn ldisc_setup(tty: Arc, _o_tty: Option>) -> Result<(), SystemError> { + let ld = tty.ldisc(); + + let ret = ld.open(tty); + if ret.is_err() { + let err = ret.unwrap_err(); + if err == SystemError::ENOSYS { + return Err(err); + } + } + + // TODO: 处理PTY + + Ok(()) + } +} diff --git a/kernel/src/driver/tty/tty_ldisc/ntty.rs b/kernel/src/driver/tty/tty_ldisc/ntty.rs new file mode 100644 index 00000000..66fd48dc --- /dev/null +++ b/kernel/src/driver/tty/tty_ldisc/ntty.rs @@ -0,0 +1,2016 @@ +use core::ops::BitXor; + +use bitmap::{traits::BitMapOps, StaticBitmap}; + +use alloc::sync::{Arc, Weak}; +use system_error::SystemError; + +use crate::{ + arch::ipc::signal::Signal, + driver::tty::{ + termios::{ControlCharIndex, InputMode, LocalMode, OutputMode, Termios}, + tty_core::{EchoOperation, TtyCore, TtyCoreData, TtyFlag, TtyIoctlCmd}, + tty_driver::{TtyDriverFlag, TtyOperation}, + tty_job_control::TtyJobCtrlManager, + }, + filesystem::vfs::file::FileMode, + libs::{ + rwlock::RwLockReadGuard, + spinlock::{SpinLock, SpinLockGuard}, + }, + mm::VirtAddr, + net::event_poll::EPollEventType, + process::ProcessManager, + syscall::{user_access::UserBufferWriter, Syscall}, +}; + +use super::TtyLineDiscipline; +pub const NTTY_BUFSIZE: usize = 4096; +pub const ECHO_COMMIT_WATERMARK: usize = 256; +pub const ECHO_BLOCK: usize = 256; +pub const ECHO_DISCARD_WATERMARK: usize = NTTY_BUFSIZE - (ECHO_BLOCK + 32); + +fn ntty_buf_mask(idx: usize) -> usize { + return idx & (NTTY_BUFSIZE - 1); +} + +#[derive(Debug)] +pub struct NTtyLinediscipline { + pub data: SpinLock, +} + +impl NTtyLinediscipline { + #[inline] + pub fn disc_data(&self) -> SpinLockGuard { + self.data.lock_irqsave() + } + + #[inline] + pub fn disc_data_try_lock(&self) -> Result, SystemError> { + self.data.try_lock_irqsave() + } + + fn ioctl_helper(&self, tty: Arc, cmd: u32, arg: usize) -> Result { + match cmd { + TtyIoctlCmd::TCXONC => { + todo!() + } + TtyIoctlCmd::TCFLSH => { + todo!() + } + _ => { + return tty.tty_mode_ioctl(tty.clone(), cmd, arg); + } + } + } +} + +#[derive(Debug)] +pub struct NTtyData { + /// 写者管理,tty只有一个写者,即ttydevice,所以不需要加锁 + /// 读取缓冲区的头指针,表示下一个将要接受进buf的字符的位置 + read_head: usize, + /// 提交缓冲区的头指针,用于行规程处理 + commit_head: usize, + /// 规范缓冲区的头指针,用于规范模式的处理 + canon_head: usize, + /// 回显缓冲区的头指针,用于存储需要回显的字符 + echo_head: usize, + /// 回显过程中用于提交的头指针 + echo_commit: usize, + /// 标记回显字符的起始位置 + echo_mark: usize, + + /// 读者管理 + /// 读取字符的尾指针,即当前读取位置 + read_tail: usize, + /// 行的起始位置 + line_start: usize, + /// 预读字符数,用于处理控制字符 + lookahead_count: usize, + + // 更改以下六个标记时必须持有termios的锁 + /// Line-next 标志,表示下一个输入字符应当按字面处理 + lnext: bool, + /// 擦除状态的标志 + erasing: bool, + /// Raw 模式的标志 + raw: bool, + /// Real raw 模式的标志 + real_raw: bool, + /// 规范模式的标志 + icanon: bool, + /// 是否开启echo + echo: bool, + /// 标志是否正在进行推送 + pushing: bool, + /// 是否没有空间可写 + no_room: bool, + + /// 光标所在列 + cursor_column: u32, + /// 规范模式下光标所在列 + canon_cursor_column: u32, + /// 回显缓冲区的尾指针 + echo_tail: usize, + + /// 写者与读者共享 + read_buf: [u8; NTTY_BUFSIZE], + echo_buf: [u8; NTTY_BUFSIZE], + + read_flags: StaticBitmap, + char_map: StaticBitmap<256>, + + tty: Option>, +} + +impl NTtyData { + pub fn new() -> Self { + Self { + read_head: 0, + commit_head: 0, + canon_head: 0, + echo_head: 0, + echo_commit: 0, + echo_mark: 0, + read_tail: 0, + line_start: 0, + lookahead_count: 0, + lnext: false, + erasing: false, + raw: false, + real_raw: false, + icanon: false, + pushing: false, + echo: false, + cursor_column: 0, + canon_cursor_column: 0, + echo_tail: 0, + read_buf: [0; NTTY_BUFSIZE], + echo_buf: [0; NTTY_BUFSIZE], + read_flags: StaticBitmap::new(), + char_map: StaticBitmap::new(), + tty: None, + no_room: false, + } + } + + #[inline] + pub fn read_cnt(&self) -> usize { + self.read_head - self.read_tail + } + + #[inline] + pub fn read_at(&self, i: usize) -> u8 { + let i = i & (NTTY_BUFSIZE - 1); + self.read_buf[i] + } + + /// ### 接收数据到NTTY + pub fn receive_buf_common( + &mut self, + tty: Arc, + buf: &[u8], + flags: Option<&[u8]>, + mut count: usize, + flow: bool, + ) -> Result { + // 获取termios读锁 + let termios = tty.core().termios(); + let mut overflow; + let mut n; + let mut offset = 0; + let mut recved = 0; + loop { + let tail = self.read_tail; + + let mut room = NTTY_BUFSIZE - (self.read_head - tail); + if termios.input_mode.contains(InputMode::PARMRK) { + room = (room + 2) / 3; + } + + room -= 1; + if room == 0 || room > NTTY_BUFSIZE { + // 可能溢出 + overflow = self.icanon && self.canon_head == tail; + if room > NTTY_BUFSIZE && overflow { + self.read_head -= 1; + } + self.no_room = flow && !overflow; + room = if overflow { !0 } else { 0 } + } else { + overflow = false; + } + + n = count.min(room); + if n == 0 { + break; + } + + if !overflow { + if flags.is_none() { + self.receive_buf(tty.clone(), &buf[offset..], flags, n); + } else { + self.receive_buf( + tty.clone(), + &buf[offset..], + Some(&flags.unwrap()[offset..]), + n, + ); + } + } + + offset += n; + + count -= n; + + recved += n; + + if tty.core().flags().contains(TtyFlag::LDISC_CHANGING) { + break; + } + } + + // TODO: throttle + + Ok(recved) + } + + pub fn receive_buf( + &mut self, + tty: Arc, + buf: &[u8], + flags: Option<&[u8]>, + count: usize, + ) { + let termios = tty.core().termios(); + let preops = termios.input_mode.contains(InputMode::ISTRIP) + || termios.input_mode.contains(InputMode::IUCLC) + || termios.local_mode.contains(LocalMode::IEXTEN); + + let look_ahead = self.lookahead_count.min(count); + + if self.real_raw { + todo!("tty real raw mode todo"); + } else if self.raw || (termios.local_mode.contains(LocalMode::EXTPROC) && !preops) { + todo!("tty raw mode todo"); + } else if tty.core().is_closing() && !termios.local_mode.contains(LocalMode::EXTPROC) { + todo!() + } else { + if look_ahead > 0 { + self.receive_buf_standard(tty.clone(), buf, flags, look_ahead, true); + } + + if count > look_ahead { + self.receive_buf_standard(tty.clone(), buf, flags, count - look_ahead, false); + } + + // 刷新echo + self.flush_echoes(tty.clone()); + + tty.flush_chars(tty.core()); + } + + self.lookahead_count -= look_ahead; + + if self.icanon && !termios.local_mode.contains(LocalMode::EXTPROC) { + return; + } + + self.commit_head = self.read_head; + + if self.read_cnt() > 0 { + tty.core() + .read_wq() + .wakeup((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDBAND).bits() as u64); + } + } + + pub fn flush_echoes(&mut self, tty: Arc) { + let termios = tty.core().termios(); + if !termios.local_mode.contains(LocalMode::ECHO) + && !termios.local_mode.contains(LocalMode::ECHONL) + || self.echo_commit == self.echo_head + { + return; + } + + self.echo_commit = self.echo_head; + drop(termios); + let _ = self.echoes(tty); + } + + pub fn receive_buf_standard( + &mut self, + tty: Arc, + buf: &[u8], + flags: Option<&[u8]>, + mut count: usize, + lookahead_done: bool, + ) { + let termios = tty.core().termios(); + if flags.is_some() { + todo!("ntty recv buf flags todo"); + } + + let mut offset = 0; + while count > 0 { + if offset >= buf.len() { + break; + } + let mut c = buf[offset]; + offset += 1; + + if self.lnext { + // 将下一个字符当做字面值处理 + self.lnext = false; + if termios.input_mode.contains(InputMode::ISTRIP) { + c &= 0x7f; + } + + if termios.input_mode.contains(InputMode::IUCLC) + && termios.local_mode.contains(LocalMode::IEXTEN) + { + c = (c as char).to_ascii_lowercase() as u8; + self.receive_char(c, tty.clone()) + } + + continue; + } + + if termios.input_mode.contains(InputMode::ISTRIP) { + c &= 0x7f; + } + + if termios.input_mode.contains(InputMode::IUCLC) + && termios.local_mode.contains(LocalMode::IEXTEN) + { + c = (c as char).to_ascii_lowercase() as u8; + } + + if termios.local_mode.contains(LocalMode::EXTPROC) { + self.add_read_byte(c); + continue; + } + + if self.char_map.get(c as usize).unwrap() { + // 特殊字符 + self.receive_special_char(c, tty.clone(), lookahead_done) + } else { + self.receive_char(c, tty.clone()); + } + + count -= 1; + } + } + + pub fn receive_special_char(&mut self, mut c: u8, tty: Arc, lookahead_done: bool) { + let is_flow_ctrl = self.is_flow_ctrl_char(tty.clone(), c, lookahead_done); + let termios = tty.core().termios(); + + // 启用软件流控,并且该字符已经当做软件流控字符处理 + if termios.input_mode.contains(InputMode::IXON) && is_flow_ctrl { + return; + } + + if termios.local_mode.contains(LocalMode::ISIG) { + if c == termios.control_characters[ControlCharIndex::VINTR] { + self.recv_sig_char(tty.clone(), &termios, Signal::SIGINT, c); + return; + } + + if c == termios.control_characters[ControlCharIndex::VQUIT] { + self.recv_sig_char(tty.clone(), &termios, Signal::SIGQUIT, c); + return; + } + + if c == termios.control_characters[ControlCharIndex::VSUSP] { + self.recv_sig_char(tty.clone(), &termios, Signal::SIGTSTP, c); + return; + } + } + + let flow = tty.core().flow_irqsave(); + if flow.stopped + && !flow.tco_stopped + && termios.input_mode.contains(InputMode::IXON) + && termios.input_mode.contains(InputMode::IXANY) + { + tty.tty_start(); + self.process_echoes(tty.clone()); + } + drop(flow); + + if c == b'\r' { + if termios.input_mode.contains(InputMode::IGNCR) { + // 忽略 + return; + } + if termios.input_mode.contains(InputMode::ICRNL) { + // 映射为换行 + c = b'\n'; + } + } else if c == b'\n' && termios.input_mode.contains(InputMode::INLCR) { + // 映射为回车 + c = b'\r'; + } + + if self.icanon { + if c == termios.control_characters[ControlCharIndex::VERASE] + || c == termios.control_characters[ControlCharIndex::VKILL] + || (c == termios.control_characters[ControlCharIndex::VWERASE] + && termios.local_mode.contains(LocalMode::IEXTEN)) + { + self.eraser(c, &termios); + self.commit_echoes(tty.clone()); + return; + } + if c == termios.control_characters[ControlCharIndex::VLNEXT] + && termios.local_mode.contains(LocalMode::IEXTEN) + { + self.lnext = true; + if termios.local_mode.contains(LocalMode::ECHO) { + self.finish_erasing(); + if termios.local_mode.contains(LocalMode::ECHOCTL) { + self.echo_char_raw(b'^'); + self.echo_char_raw(8); + self.commit_echoes(tty.clone()); + } + } + return; + } + if c == termios.control_characters[ControlCharIndex::VREPRINT] + && termios.local_mode.contains(LocalMode::ECHO) + && termios.local_mode.contains(LocalMode::IEXTEN) + { + let mut tail = self.canon_head; + self.finish_erasing(); + self.echo_char(c, &termios); + self.echo_char_raw(b'\n'); + while ntty_buf_mask(tail) != ntty_buf_mask(self.read_head) { + self.echo_char(self.read_buf[ntty_buf_mask(tail)], &termios); + tail += 1; + } + self.commit_echoes(tty.clone()); + return; + } + + if c == b'\n' { + if termios.local_mode.contains(LocalMode::ECHO) + || termios.local_mode.contains(LocalMode::ECHONL) + { + self.echo_char_raw(b'\n'); + self.commit_echoes(tty.clone()); + } + + self.read_flags.set(ntty_buf_mask(self.read_head), true); + self.read_buf[ntty_buf_mask(self.read_head)] = c; + self.read_head += 1; + self.canon_head = self.read_head; + tty.core() + .read_wq() + .wakeup((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64); + return; + } + + if c == termios.control_characters[ControlCharIndex::VEOF] { + c = ControlCharIndex::DISABLE_CHAR; + + self.read_flags.set(ntty_buf_mask(self.read_head), true); + self.read_buf[ntty_buf_mask(self.read_head)] = c; + self.read_head += 1; + self.canon_head = self.read_head; + tty.core() + .read_wq() + .wakeup((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64); + return; + } + + if c == termios.control_characters[ControlCharIndex::VEOL] + || (c == termios.control_characters[ControlCharIndex::VEOL2] + && termios.local_mode.contains(LocalMode::IEXTEN)) + { + if termios.local_mode.contains(LocalMode::ECHO) { + if self.canon_head == self.read_head { + self.add_echo_byte(EchoOperation::Start.to_u8()); + self.add_echo_byte(EchoOperation::SetCanonCol.to_u8()); + } + self.echo_char(c, &termios); + self.commit_echoes(tty.clone()); + } + + if c == 0o377 && termios.input_mode.contains(InputMode::PARMRK) { + self.read_buf[ntty_buf_mask(self.read_head)] = c; + self.read_head += 1; + } + + self.read_flags.set(ntty_buf_mask(self.read_head), true); + self.read_buf[ntty_buf_mask(self.read_head)] = c; + self.read_head += 1; + self.canon_head = self.read_head; + tty.core() + .read_wq() + .wakeup((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64); + return; + } + } + + if termios.local_mode.contains(LocalMode::ECHO) { + self.finish_erasing(); + if c == b'\n' { + self.echo_char_raw(b'\n'); + } else { + if self.canon_head == self.read_head { + self.add_echo_byte(EchoOperation::Start.to_u8()); + self.add_echo_byte(EchoOperation::SetCanonCol.to_u8()); + } + self.echo_char(c, &termios); + } + + self.commit_echoes(tty.clone()); + } + + if c == 0o377 && termios.input_mode.contains(InputMode::PARMRK) { + self.read_buf[ntty_buf_mask(self.read_head)] = c; + self.read_head += 1; + } + + self.read_buf[ntty_buf_mask(self.read_head)] = c; + self.read_head += 1; + } + + /// ## ntty默认eraser function + fn eraser(&mut self, mut c: u8, termios: &RwLockReadGuard) { + if self.read_head == self.canon_head { + return; + } + + let erase = c == termios.control_characters[ControlCharIndex::VERASE]; + let werase = c == termios.control_characters[ControlCharIndex::VWERASE]; + let kill = !erase && !werase; + + if kill { + if !termios.local_mode.contains(LocalMode::ECHO) { + self.read_head = self.canon_head; + return; + } + if !termios.local_mode.contains(LocalMode::ECHOK) + || !termios.local_mode.contains(LocalMode::ECHOKE) + || !termios.local_mode.contains(LocalMode::ECHOE) + { + self.read_head = self.canon_head; + if self.erasing { + self.echo_char_raw(c); + self.erasing = false; + } + self.echo_char(c, termios); + + if termios.local_mode.contains(LocalMode::ECHOK) { + // 添加新行 + self.echo_char_raw(b'\n'); + } + return; + } + } + + let mut head; + let mut cnt; + while ntty_buf_mask(self.read_head) != ntty_buf_mask(self.canon_head) { + head = self.read_head; + + loop { + // 消除多字节字符 + head -= 1; + c = self.read_buf[ntty_buf_mask(head)]; + + if !(Self::is_continuation(c, termios) + && ntty_buf_mask(head) != ntty_buf_mask(self.canon_head)) + { + break; + } + } + + if Self::is_continuation(c, termios) { + break; + } + + if werase { + todo!() + } + + cnt = self.read_head - head; + self.read_head = head; + if termios.local_mode.contains(LocalMode::ECHO) { + if termios.local_mode.contains(LocalMode::ECHOPRT) { + if !self.erasing { + self.echo_char_raw(b'\\'); + self.erasing = true; + } + self.echo_char(c, termios); + cnt -= 1; + while cnt > 0 { + cnt -= 1; + head += 1; + self.echo_char_raw(self.read_buf[ntty_buf_mask(head)]); + self.add_echo_byte(EchoOperation::Start.to_u8()); + self.add_echo_byte(EchoOperation::MoveBackCol.to_u8()); + } + } else if erase && !termios.local_mode.contains(LocalMode::ECHOE) { + self.echo_char( + termios.control_characters[ControlCharIndex::VERASE], + termios, + ); + } else if c == b'\t' { + let mut num_chars = 0; + let mut after_tab = false; + let mut tail = self.read_head; + + while ntty_buf_mask(tail) != ntty_buf_mask(self.canon_head) { + tail -= 1; + c = self.read_buf[ntty_buf_mask(tail)]; + if c == b'\t' { + after_tab = true; + break; + } else if (c as char).is_control() { + if termios.local_mode.contains(LocalMode::ECHOCTL) { + num_chars += 2; + } + } else if !Self::is_continuation(c, termios) { + num_chars += 1; + } + } + + self.echo_erase_tab(num_chars, after_tab); + } else { + if (c as char).is_control() && termios.local_mode.contains(LocalMode::ECHOCTL) { + // 8 => '\b' + self.echo_char_raw(8); + self.echo_char_raw(b' '); + self.echo_char_raw(8); + } + + if !(c as char).is_control() || termios.local_mode.contains(LocalMode::ECHOCTL) + { + // 8 => '\b' + self.echo_char_raw(8); + self.echo_char_raw(b' '); + self.echo_char_raw(8); + } + } + } + + if erase { + break; + } + } + + if self.read_head == self.canon_head && termios.local_mode.contains(LocalMode::ECHO) { + self.finish_erasing(); + } + } + + fn finish_erasing(&mut self) { + if self.erasing { + self.echo_char_raw(b'/'); + self.erasing = false; + } + } + + fn echo_erase_tab(&mut self, mut num: u8, after_tab: bool) { + self.add_echo_byte(EchoOperation::Start.to_u8()); + self.add_echo_byte(EchoOperation::EraseTab.to_u8()); + + num &= 7; + + if after_tab { + num |= 0x80; + } + + self.add_echo_byte(num); + } + + /// ## 多字节字符检测 + /// 检测是否为多字节字符的后续字节 + fn is_continuation(c: u8, termios: &RwLockReadGuard) -> bool { + return termios.input_mode.contains(InputMode::IUTF8) && (c & 0xc0) == 0x80; + } + + /// ## 该字符是否已经当做流控字符处理 + pub fn is_flow_ctrl_char(&mut self, tty: Arc, c: u8, lookahead_done: bool) -> bool { + let termios = tty.core().termios(); + + if !(termios.control_characters[ControlCharIndex::VSTART] == c + || termios.control_characters[ControlCharIndex::VSTOP] == c) + { + return false; + } + + if lookahead_done { + return true; + } + + if termios.control_characters[ControlCharIndex::VSTART] == c { + tty.tty_start(); + self.process_echoes(tty.clone()); + return true; + } else { + tty.tty_stop(); + return true; + } + } + + /// ## 接收到信号字符时的处理 + fn recv_sig_char( + &mut self, + tty: Arc, + termios: &RwLockReadGuard, + signal: Signal, + c: u8, + ) { + self.input_signal(tty.clone(), termios, signal); + if termios.input_mode.contains(InputMode::IXON) { + tty.tty_start(); + } + + if termios.local_mode.contains(LocalMode::ECHO) { + self.echo_char(c, termios); + self.commit_echoes(tty); + } else { + self.process_echoes(tty); + } + } + + /// ## 处理输入信号 + pub fn input_signal( + &mut self, + tty: Arc, + termios: &RwLockReadGuard, + signal: Signal, + ) { + // 先处理信号 + let mut ctrl_info = tty.core().contorl_info_irqsave(); + let pg = ctrl_info.pgid; + if pg.is_some() { + let _ = Syscall::kill(pg.unwrap(), signal as i32); + } + + ctrl_info.pgid = None; + ctrl_info.session = None; + + if !termios.local_mode.contains(LocalMode::NOFLSH) { + // 重置 + self.echo_head = 0; + self.echo_tail = 0; + self.echo_mark = 0; + self.echo_commit = 0; + + let _ = tty.flush_buffer(tty.core()); + + self.read_head = 0; + self.canon_head = 0; + self.read_tail = 0; + self.line_start = 0; + + self.erasing = false; + self.read_flags.set_all(false); + self.pushing = false; + self.lookahead_count = 0; + } + } + + pub fn receive_char(&mut self, c: u8, tty: Arc) { + let termios = tty.core().termios(); + + if termios.local_mode.contains(LocalMode::ECHO) { + if self.erasing { + self.add_echo_byte(b'/'); + self.erasing = false; + } + + if self.canon_head == self.read_head { + self.add_echo_byte(EchoOperation::Start.to_u8()); + self.add_echo_byte(EchoOperation::SetCanonCol.to_u8()); + } + + self.echo_char(c, &termios); + self.commit_echoes(tty.clone()); + } + + if c == 0o377 && tty.core().termios().input_mode.contains(InputMode::PARMRK) { + self.add_read_byte(c); + } + self.add_read_byte(c); + } + + pub fn echo_char(&mut self, c: u8, termios: &RwLockReadGuard) { + if c == EchoOperation::Start.to_u8() { + self.add_echo_byte(EchoOperation::Start.to_u8()); + self.add_echo_byte(EchoOperation::Start.to_u8()); + } else { + if termios.local_mode.contains(LocalMode::ECHOCTL) + && (c as char).is_control() + && c != b'\t' + { + self.add_echo_byte(EchoOperation::Start.to_u8()); + } + self.add_echo_byte(c); + } + } + + pub fn echo_char_raw(&mut self, c: u8) { + if c == EchoOperation::Start.to_u8() { + self.add_echo_byte(EchoOperation::Start.to_u8()); + self.add_echo_byte(EchoOperation::Start.to_u8()); + } else { + self.add_echo_byte(c); + } + } + + /// ## 提交echobuf里的数据显示 + pub fn commit_echoes(&mut self, tty: Arc) { + let head = self.echo_head; + self.echo_mark = head; + let old = self.echo_commit - self.echo_tail; + + // 需要echo的字符个数 + let nr = head - self.echo_tail; + + if nr < ECHO_COMMIT_WATERMARK || nr % ECHO_BLOCK > old % ECHO_BLOCK { + return; + } + + self.echo_commit = head; + let echoed = self.echoes(tty.clone()); + + if echoed.is_ok() && echoed.unwrap() > 0 { + tty.flush_chars(tty.core()); + } + } + + pub fn add_echo_byte(&mut self, c: u8) { + self.echo_buf[ntty_buf_mask(self.echo_head)] = c; + self.echo_head += 1; + } + + pub fn add_read_byte(&mut self, c: u8) { + self.read_buf[ntty_buf_mask(self.read_head)] = c; + self.read_head += 1; + } + + /// ### 将read_buffer的部分值置0 + /// + /// 只会在规范模式和禁用echo下执行 + #[inline] + pub fn zero_buffer(&mut self, offset: usize, size: usize) { + let offset = offset & (NTTY_BUFSIZE - 1); + if self.icanon && !self.echo { + let n = offset + size; + if n > NTTY_BUFSIZE { + for c in &mut self.read_buf[offset..NTTY_BUFSIZE] { + *c = 0 + } + + for c in &mut self.read_buf[0..(n - NTTY_BUFSIZE)] { + *c = 0 + } + } else { + for c in &mut self.read_buf[offset..n] { + *c = 0 + } + }; + } + } + + /// ## 从ntty中拷贝数据 + /// + /// ### 参数 + /// + /// ### to: 存储数据 + /// ### tail: 读取尾 + pub fn ntty_copy( + &mut self, + to: &mut [u8], + tail: usize, + n: &mut usize, + ) -> Result<(), SystemError> { + if to.len() < *n { + *n = to.len(); + // return Err(SystemError::EINVAL); + } + if tail > NTTY_BUFSIZE { + return Err(SystemError::EINVAL); + } + + let size = NTTY_BUFSIZE - tail; + + if size < *n { + // 有一部分数据在头部,则先拷贝后面部分,再拷贝头部 + // TODO: tty审计? + to[0..size].copy_from_slice(&self.read_buf[tail..(tail + size)]); + to[size..].copy_from_slice(&self.read_buf[(tail + size)..(*n + tail)]); + } else { + to[..*n].copy_from_slice(&self.read_buf[tail..(tail + *n)]) + } + + self.zero_buffer(tail, *n); + + Ok(()) + } + + /// ## 规范模式下跳过EOF + pub fn canon_skip_eof(&mut self) { + // 没有数据 + if self.read_tail == self.canon_head { + return; + } + + let tail = self.read_tail & (NTTY_BUFSIZE - 1); + + // 查看read_flags是否读取位置为特殊字符 + if !self.read_flags.get(tail).unwrap() { + return; + } + + // 确保读取位置是'\0'字符 + if self.read_buf[tail] != ControlCharIndex::DISABLE_CHAR { + return; + } + + // 处理该字符,将read_flagsw该位清除 + self.read_flags.set(tail, false); + // 读取位置+1,即跳过该字符不做处理 + self.read_tail += 1; + } + + /// ## 在规范模式(canonical mode)下从读缓冲中复制一行 + /// + /// 一次只拷贝一行 + /// + /// ## 参数 + /// ### dst: 存放数据 + /// ### nr: 需要拷贝的数据大小 + /// + /// ## 返回值 + /// ### true: 表示一行未结束并且还有数据可读 + /// ### false: 一行已结束或者没有数据可读 + pub fn canon_copy_from_read_buf( + &mut self, + dst: &mut [u8], + nr: &mut usize, + offset: &mut usize, + ) -> Result { + if *nr == 0 { + return Ok(false); + } + + let canon_head = self.canon_head; + + // 取得能够读到的字符数,即canon_head - self.read_tail和nr最小值 + let mut n = (*nr).min(canon_head - self.read_tail); + + // 获得读尾index + let tail = self.read_tail & (NTTY_BUFSIZE - 1); + + // 避免越界,这个size才是实际读取大小 + let size = if tail + n > NTTY_BUFSIZE { + NTTY_BUFSIZE + } else { + tail + *nr + }; + + // 找到eol的坐标 + let tmp = self.read_flags.next_index(tail); + // 找到的话即为坐标,未找到的话即为NTTY_BUFSIZE + let mut eol = if tmp.is_none() { size } else { tmp.unwrap() }; + if eol > size { + eol = size + } + + // 是否需要绕回缓冲区头部 + let more = n - (size - tail); + + // 是否找到eol + let found = if eol == NTTY_BUFSIZE && more > 0 { + // 需要返回头部 + let ret = self.read_flags.first_index(); + if ret.is_some() { + let tmp = ret.unwrap(); + // 在头部范围内找到eol + if tmp < more { + eol = tmp; + } + } else { + eol = more; + } + eol != more + } else { + // 不需要返回头部 + eol != size + }; + + n = eol - tail; + if n > NTTY_BUFSIZE { + // 减法溢出则加上BUFSIZE即可限制在0-NTTY_BUFSIZE内 + n += NTTY_BUFSIZE; + } + + // 规范模式下实际扫描过的字符数,需要将eol计算在内 + let count = if found { n + 1 } else { n }; + + // 表示这一行未结束 + if !found || self.read_at(eol) != ControlCharIndex::DISABLE_CHAR { + n = count; + } + + self.ntty_copy(&mut dst[*offset..], tail, &mut n)?; + *nr -= n; + *offset += n; + + if found { + self.read_flags.set(eol, false); + } + + self.read_tail += count; + + if found { + if !self.pushing { + self.line_start = self.read_tail; + } else { + self.pushing = false; + } + + // todo: 审计? + return Ok(false); + } + + // 这里是表示没有找到eol,根据是否还有数据可读返回 + Ok(self.read_tail != canon_head) + } + + /// ## 根据终端的模式和输入缓冲区中的数据量,判断是否可读字符 + pub fn input_available(&self, termios: RwLockReadGuard, poll: bool) -> bool { + // 计算最小字符数 + let amt = if poll + && termios.control_characters[ControlCharIndex::VTIME] as u32 == 0 + && termios.control_characters[ControlCharIndex::VMIN] as u32 != 0 + { + termios.control_characters[ControlCharIndex::VMIN] as usize + } else { + 1 + }; + + // 规范模式且非拓展 + if self.icanon && !termios.local_mode.contains(LocalMode::EXTPROC) { + return self.canon_head != self.read_tail; + } else { + return (self.commit_head - self.read_tail) >= amt; + } + } + + /// ## 非规范模式下从read_buf读取数据 + /// + /// ## 参数 + /// ### termios: tty对应的termioss读锁守卫 + /// ### dst: 存储读取数据 + /// ### nr: 读取长度 + /// + /// ## 返回值 + /// ### true: 还有更多数据可读 + /// ### false: 无更多数据可读 + pub fn copy_from_read_buf( + &mut self, + termios: RwLockReadGuard, + dst: &mut [u8], + nr: &mut usize, + offset: &mut usize, + ) -> Result { + let head = self.commit_head; + let tail = self.read_tail & (NTTY_BUFSIZE - 1); + + // 计算出可读的字符数 + let mut n = (NTTY_BUFSIZE - tail).min(self.read_tail); + n = n.min(*nr); + + if n > 0 { + // 拷贝数据 + self.ntty_copy(&mut dst[*offset..], tail, &mut n)?; + // todo:审计? + self.read_tail += n; + + // 是否只读取了eof + let eof = + n == 1 && self.read_buf[tail] == termios.control_characters[ControlCharIndex::VEOF]; + + if termios.local_mode.contains(LocalMode::EXTPROC) + && self.icanon + && eof + && head == self.read_tail + { + return Ok(false); + } + + *nr -= n; + *offset += n; + + return Ok(head != self.read_tail); + } + + Ok(false) + } + + /// ## 用于处理带有 OPOST(Output Post-processing)标志的输出块的函数 + /// OPOST 是 POSIX 终端驱动器标志之一,用于指定在写入终端设备之前对输出数据进行一些后期处理。 + pub fn process_output_block( + &mut self, + core: &TtyCoreData, + termios: RwLockReadGuard, + buf: &[u8], + nr: usize, + ) -> Result { + let mut nr = nr; + let tty = self.tty.clone().unwrap().upgrade().unwrap(); + let space = tty.write_room(tty.core()); + + // 如果读取数量大于了可用空间,则取最小的为真正的写入数量 + if nr > space { + nr = space + } + + let mut cnt = 0; + for i in 0..nr { + cnt = i; + let c = buf[i]; + if c as usize == 8 { + // 表示退格 + if self.cursor_column > 0 { + self.cursor_column -= 1; + } + continue; + } + match c as char { + '\n' => { + if termios.output_mode.contains(OutputMode::ONLRET) { + // 将回车映射为\n,即将\n换为回车 + self.cursor_column = 0; + } + if termios.output_mode.contains(OutputMode::ONLCR) { + // 输出时将\n换为\r\n + break; + } + + self.canon_cursor_column = self.cursor_column; + } + '\r' => { + if termios.output_mode.contains(OutputMode::ONOCR) && self.cursor_column == 0 { + // 光标已经在第0列,则不输出回车符 + break; + } + + if termios.output_mode.contains(OutputMode::OCRNL) { + break; + } + self.canon_cursor_column = self.cursor_column; + } + '\t' => { + break; + } + _ => { + // 判断是否为控制字符 + if !(c as char).is_control() { + if termios.output_mode.contains(OutputMode::OLCUC) { + break; + } + + // 判断是否为utf8模式下的连续字符 + if !(termios.input_mode.contains(InputMode::IUTF8) + && (c as usize) & 0xc0 == 0x80) + { + self.cursor_column += 1; + } + } + } + } + } + + drop(termios); + return tty.write(core, buf, cnt); + } + + /// ## 处理回显 + pub fn process_echoes(&mut self, tty: Arc) { + if self.echo_mark == self.echo_tail { + return; + } + self.echo_commit = self.echo_mark; + let echoed = self.echoes(tty.clone()); + + if echoed.is_ok() && echoed.unwrap() > 0 { + let _ = tty.flush_chars(tty.core()); + } + } + + pub fn echoes(&mut self, tty: Arc) -> Result { + let mut space = tty.write_room(tty.core()); + let ospace = space; + let termios = tty.core().termios(); + let core = tty.core(); + let mut tail = self.echo_tail; + + while ntty_buf_mask(self.echo_commit) != ntty_buf_mask(tail) { + let c = self.echo_buf[ntty_buf_mask(tail)]; + + if EchoOperation::from_u8(c) == EchoOperation::Start { + if ntty_buf_mask(self.echo_commit) == ntty_buf_mask(tail + 1) { + self.echo_tail = tail; + return Ok(ospace - space); + } + + // 获取到start,之后取第一个作为op + let op = EchoOperation::from_u8(self.echo_buf[ntty_buf_mask(tail + 1)]); + + match op { + EchoOperation::Start => { + if space == 0 { + break; + } + + if tty + .put_char(tty.core(), EchoOperation::Start.to_u8()) + .is_err() + { + tty.write(core, &[EchoOperation::Start.to_u8()], 1)?; + } + + self.cursor_column += 1; + space -= 1; + tail += 2; + } + EchoOperation::MoveBackCol => { + if self.cursor_column > 0 { + self.cursor_column -= 1; + } + tail += 2; + } + EchoOperation::SetCanonCol => { + self.canon_cursor_column = self.cursor_column; + tail += 2; + } + EchoOperation::EraseTab => { + if ntty_buf_mask(self.echo_commit) == ntty_buf_mask(tail + 2) { + self.echo_tail = tail; + return Ok(ospace - space); + } + + // 要擦除的制表符所占用的列数 + let mut char_num = self.echo_buf[ntty_buf_mask(tail + 2)] as usize; + + /* + 如果 num_chars 的最高位(0x80)未设置, + 表示这是从输入的起始位置而不是从先前的制表符开始计算的列数。 + 在这种情况下,将 num_chars 与 ldata->canon_column 相加,否则,列数就是正常的制表符列数。 + */ + if char_num & 0x80 == 0 { + char_num += self.canon_cursor_column as usize; + } + + // 计算要回退的列数,即制表符宽度减去实际占用的列数 + let mut num_bs = 8 - (char_num & 7); + if num_bs > space { + // 表示左边没有足够空间回退 + break; + } + + space -= num_bs; + while num_bs != 0 { + num_bs -= 1; + // 8 => '\b' + if tty.put_char(tty.core(), 8).is_err() { + tty.write(core, &[8], 1)?; + } + + if self.cursor_column > 0 { + self.cursor_column -= 1; + } + } + + // 已经读取了 tail tail+1 tail+2,所以这里偏移加3 + tail += 3; + } + EchoOperation::Undefined(ch) => { + match ch { + 8 => { + if tty.put_char(tty.core(), 8).is_err() { + tty.write(core, &[8], 1)?; + } + if tty.put_char(tty.core(), ' ' as u8).is_err() { + tty.write(core, &[' ' as u8], 1)?; + } + self.cursor_column -= 1; + space -= 1; + tail += 1; + } + _ => { + // 不是特殊字节码,则表示控制字符 例如 ^C + if space < 2 { + break; + } + + if tty.put_char(tty.core(), b'^').is_err() { + tty.write(core, &[b'^'], 1)?; + } + + if tty.put_char(tty.core(), ch ^ 0o100).is_err() { + tty.write(core, &[ch ^ 0o100], 1)?; + } + + self.cursor_column += 2; + space -= 2; + tail += 2; + } + } + } + } + } else { + if termios.output_mode.contains(OutputMode::OPOST) { + let ret = self.do_output_char(tty.clone(), c, space); + + if ret.is_err() { + break; + } + space -= ret.unwrap(); + } else { + if space == 0 { + break; + } + + if tty.put_char(tty.core(), c).is_err() { + tty.write(core, &[c], 1)?; + } + space -= 1; + } + tail += 1; + } + } + + // 如果回显缓冲区接近满(在下一次提交之前可能会发生回显溢出的情况),则丢弃足够的尾部数据以防止随后的溢出。 + while self.echo_commit > tail && self.echo_commit - tail >= ECHO_DISCARD_WATERMARK { + if self.echo_buf[ntty_buf_mask(tail)] == EchoOperation::Start.to_u8() { + if self.echo_buf[ntty_buf_mask(tail + 1)] == EchoOperation::EraseTab.to_u8() { + tail += 3; + } else { + tail += 2; + } + } else { + tail += 1; + } + } + + self.echo_tail = tail; + return Ok(ospace - space); + } + + /// ## 处理输出字符(带有 OPOST 处理) + pub fn process_output(&mut self, tty: Arc, c: u8) -> bool { + let space = tty.write_room(tty.core()); + + if self.do_output_char(tty, c, space).is_err() { + return false; + } + + true + } + + // ## 设置带有 OPOST 处理的tty输出一个字符 + pub fn do_output_char( + &mut self, + tty: Arc, + c: u8, + space: usize, + ) -> Result { + if space == 0 { + return Err(SystemError::ENOBUFS); + } + + let termios = tty.core().termios(); + let core = tty.core(); + let mut c = c; + if c as usize == 8 { + // 表示退格 + if self.cursor_column > 0 { + self.cursor_column -= 1; + } + if tty.put_char(tty.core(), c).is_err() { + tty.write(core, &[c], 1)?; + } + return Ok(1); + } + match c as char { + '\n' => { + if termios.output_mode.contains(OutputMode::ONLRET) { + // 回车符 + self.cursor_column = 0; + } + if termios.output_mode.contains(OutputMode::ONLCR) { + // 映射为“\r\n” + if space < 2 { + return Err(SystemError::ENOBUFS); + } + self.cursor_column = 0; + self.canon_cursor_column = 0; + + // 通过驱动写入 + tty.write(core, "\r\n".as_bytes(), 2)?; + return Ok(2); + } + + self.canon_cursor_column = self.cursor_column; + } + '\r' => { + if termios.output_mode.contains(OutputMode::ONOCR) && self.cursor_column == 0 { + // 光标已经在第0列,则不输出回车符 + return Ok(0); + } + + if termios.output_mode.contains(OutputMode::OCRNL) { + // 输出的\r映射为\n + c = b'\n'; + if termios.output_mode.contains(OutputMode::ONLRET) { + // \r映射为\n,但是保留\r特性 + self.cursor_column = 0; + self.canon_cursor_column = 0; + } + } else { + self.cursor_column = 0; + self.canon_cursor_column = 0; + } + } + '\t' => { + // 计算输出一个\t需要的空间 + let spaces = 8 - (self.cursor_column & 7) as usize; + if termios.output_mode.contains(OutputMode::TABDLY) { + if OutputMode::TABDLY.bits() == OutputMode::XTABS.bits() { + // 配置的tab选项是真正输出空格到驱动 + if space < spaces { + // 空间不够 + return Err(SystemError::ENOBUFS); + } + self.cursor_column += spaces as u32; + // 写入sapces个空格 + tty.write(core, " ".as_bytes(), spaces)?; + return Ok(spaces); + } + } + self.cursor_column += spaces as u32; + } + _ => { + // 判断是否为控制字符 + if !(c as char).is_control() { + if termios.output_mode.contains(OutputMode::OLCUC) { + c = c.to_ascii_uppercase(); + } + + // 判断是否为utf8模式下的连续字符 + if !(termios.input_mode.contains(InputMode::IUTF8) + && (c as usize) & 0xc0 == 0x80) + { + self.cursor_column += 1; + } + } + } + } + + if tty.put_char(tty.core(), c).is_err() { + tty.write(core, &[c], 1)?; + } + Ok(1) + } +} + +impl TtyLineDiscipline for NTtyLinediscipline { + fn open(&self, tty: Arc) -> Result<(), system_error::SystemError> { + // 反向绑定tty到disc + self.disc_data().tty = Some(Arc::downgrade(&tty)); + // 特定的tty设备在这里可能需要取消端口节流 + return self.set_termios(tty, None); + } + + fn close(&self, _tty: Arc) -> Result<(), system_error::SystemError> { + todo!() + } + + /// ## 重置缓冲区的基本信息 + fn flush_buffer(&self, tty: Arc) -> Result<(), system_error::SystemError> { + let core = tty.core(); + let _ = core.termios(); + let mut ldata = self.disc_data(); + ldata.read_head = 0; + ldata.canon_head = 0; + ldata.read_tail = 0; + ldata.commit_head = 0; + ldata.line_start = 0; + ldata.erasing = false; + ldata.read_flags.set_all(false); + ldata.pushing = false; + ldata.lookahead_count = 0; + + // todo: kick worker? + // todo: packet mode? + + Ok(()) + } + + fn read( + &self, + tty: Arc, + buf: &mut [u8], + len: usize, + cookie: &mut bool, + _offset: usize, + mode: FileMode, + ) -> Result { + let mut ldata; + if mode.contains(FileMode::O_NONBLOCK) { + let ret = self.disc_data_try_lock(); + if ret.is_err() { + return Err(SystemError::EAGAIN_OR_EWOULDBLOCK); + } + ldata = ret.unwrap(); + } else { + ldata = self.disc_data(); + } + let core = tty.core(); + let termios = core.termios(); + let mut nr = len; + + let mut offset = 0; + + // 表示接着读 + if *cookie { + // 规范且非拓展模式 + if ldata.icanon && !termios.local_mode.contains(LocalMode::EXTPROC) { + // 跳过EOF字符 + if len == 0 { + ldata.canon_skip_eof(); + } else if ldata.canon_copy_from_read_buf(buf, &mut nr, &mut offset)? { + return Ok(len - nr); + } + } else { + if ldata.canon_copy_from_read_buf(buf, &mut nr, &mut offset)? { + return Ok(len - nr); + } + } + + // 没有数据可读 + + // todo: kick worker? or 关闭节流? + + *cookie = false; + return Ok(len - nr); + } + + drop(termios); + + TtyJobCtrlManager::tty_check_change(tty.clone(), Signal::SIGTTIN)?; + + let mut minimum: usize = 0; + if !ldata.icanon { + let core = tty.core(); + let termios = core.termios(); + minimum = termios.control_characters[ControlCharIndex::VMIN] as usize; + if minimum == 0 { + minimum = 1; + } + } + + let mut ret: Result = Ok(0); + // 记录读取前 的tail + let tail = ldata.read_tail; + drop(ldata); + while nr != 0 { + // todo: 处理packet模式 + let mut ldata = self.disc_data(); + + let core = tty.core(); + if !ldata.input_available(core.termios(), false) { + if core.flags().contains(TtyFlag::OTHER_CLOSED) { + ret = Err(SystemError::EIO); + break; + } + + if core.flags().contains(TtyFlag::HUPPED) || core.flags().contains(TtyFlag::HUPPING) + { + break; + } + + if mode.contains(FileMode::O_NONBLOCK) + || core.flags().contains(TtyFlag::LDISC_CHANGING) + { + ret = Err(SystemError::EAGAIN_OR_EWOULDBLOCK); + break; + } + + if ProcessManager::current_pcb() + .sig_info() + .sig_pending() + .has_pending() + { + ret = Err(SystemError::ERESTARTSYS); + break; + } + + // 休眠一段时间 + // 获取到termios读锁,避免termios被更改导致行为异常 + // let termios = core.termios_preempt_enable(); + // let helper = WakeUpHelper::new(ProcessManager::current_pcb()); + // let wakeup_helper = Timer::new(helper, timeout); + // wakeup_helper.activate(); + // drop(termios); + drop(ldata); + core.read_wq() + .sleep((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64); + continue; + } + + if ldata.icanon && !core.termios().local_mode.contains(LocalMode::EXTPROC) { + if ldata.canon_copy_from_read_buf(buf, &mut nr, &mut offset)? { + *cookie = true; + offset += len - nr; + return Ok(offset); + } + } else { + // 非标准模式 + // todo: 处理packet模式 + + // 拷贝数据 + if ldata.copy_from_read_buf(core.termios(), buf, &mut nr, &mut offset)? + && offset >= minimum + { + *cookie = true; + return Ok(offset); + } + } + + if offset >= minimum { + break; + } + } + let ldata = self.disc_data(); + if tail != ldata.read_tail { + // todo: kick worker? + } + + if offset > 0 { + return Ok(offset); + } + + ret + } + + fn write( + &self, + tty: Arc, + buf: &[u8], + len: usize, + mode: FileMode, + ) -> Result { + let mut nr = len; + let mut ldata = self.disc_data(); + let pcb = ProcessManager::current_pcb(); + let binding = tty.clone(); + let core = binding.core(); + let termios = core.termios().clone(); + if termios.local_mode.contains(LocalMode::TOSTOP) { + TtyJobCtrlManager::tty_check_change(tty.clone(), Signal::SIGTTOU)?; + } + + ldata.process_echoes(tty.clone()); + // drop(ldata); + let mut offset = 0; + loop { + if pcb.sig_info().sig_pending().has_pending() { + return Err(SystemError::ERESTARTSYS); + } + if core.flags().contains(TtyFlag::HUPPED) { + return Err(SystemError::EIO); + } + if termios.output_mode.contains(OutputMode::OPOST) { + while nr > 0 { + // let mut ldata = self.disc_data(); + // 获得一次处理后的数量 + let ret = ldata.process_output_block(core, core.termios(), &buf[offset..], nr); + let num = match ret { + Ok(num) => num, + Err(e) => { + if e == SystemError::EAGAIN_OR_EWOULDBLOCK { + break; + } else { + return Err(e); + } + } + }; + + offset += num; + nr -= num; + + if nr == 0 { + break; + } + + let c = buf[offset]; + if !ldata.process_output(tty.clone(), c) { + break; + } + offset += 1; + nr -= 1; + } + + let _ = tty.flush_chars(core); + } else { + while nr > 0 { + let write = tty.write(core, &buf[offset..], nr)?; + if write == 0 { + break; + } + offset += write; + nr -= write; + } + } + + if nr == 0 { + break; + } + + if mode.contains(FileMode::O_NONBLOCK) || core.flags().contains(TtyFlag::LDISC_CHANGING) + { + return Err(SystemError::EAGAIN_OR_EWOULDBLOCK); + } + + // 到这里表明没位置可写了 + // 休眠一段时间 + // 获取到termios读锁,避免termios被更改导致行为异常 + core.write_wq() + .sleep(EPollEventType::EPOLLOUT.bits() as u64); + } + + Ok(offset) + } + + fn ioctl( + &self, + tty: Arc, + cmd: u32, + arg: usize, + ) -> Result { + match cmd { + TtyIoctlCmd::TIOCOUTQ => { + let mut user_writer = UserBufferWriter::new( + VirtAddr::new(arg).as_ptr::(), + core::mem::size_of::(), + true, + )?; + + let count = tty.chars_in_buffer(); + user_writer.copy_one_to_user::(&(count as i32), 0)?; + return Ok(0); + } + TtyIoctlCmd::FIONREAD => { + let ldata = self.disc_data(); + let termios = tty.core().termios(); + let retval; + if termios.local_mode.contains(LocalMode::ICANON) + && !termios.local_mode.contains(LocalMode::EXTPROC) + { + if ldata.canon_head == ldata.read_tail { + retval = 0; + } else { + let head = ldata.canon_head; + let mut tail = ldata.read_tail; + let mut nr = head - tail; + + while ntty_buf_mask(head) != ntty_buf_mask(tail) { + if ldata.read_flags.get(ntty_buf_mask(tail)).unwrap() + && ldata.read_buf[ntty_buf_mask(tail)] + == ControlCharIndex::DISABLE_CHAR + { + nr -= 1; + } + tail += 1; + } + + retval = nr; + } + } else { + retval = ldata.read_cnt(); + } + + let mut user_writer = UserBufferWriter::new( + VirtAddr::new(arg).as_ptr::(), + core::mem::size_of::(), + true, + )?; + + user_writer.copy_one_to_user::(&(retval as i32), 0)?; + return Ok(0); + } + _ => { + return self.ioctl_helper(tty, cmd, arg); + } + } + } + + fn set_termios( + &self, + tty: Arc, + old: Option, + ) -> Result<(), system_error::SystemError> { + let core = tty.core(); + let termios = core.termios(); + let mut ldata = self.disc_data(); + let contorl_chars = termios.control_characters; + + // 第一次设置或者规范模式 (ICANON) 或者扩展处理 (EXTPROC) 标志发生变化 + if old.is_none() + || (old.is_some() + && old + .unwrap() + .local_mode + .bitxor(termios.local_mode) + .contains(LocalMode::ICANON | LocalMode::EXTPROC)) + { + // 重置read_flags + ldata.read_flags.set_all(false); + + ldata.line_start = ldata.read_tail; + + // 不是规范模式或者有可读数据 + if !termios.local_mode.contains(LocalMode::ICANON) || ldata.read_cnt() != 0 { + ldata.canon_head = ldata.read_tail; + ldata.pushing = false; + } else { + let read_head = ldata.read_head; + ldata + .read_flags + .set((read_head - 1) & (NTTY_BUFSIZE - 1), true); + ldata.canon_head = ldata.read_head; + ldata.pushing = true; + } + ldata.commit_head = ldata.read_head; + ldata.erasing = false; + ldata.lnext = false; + } + + // 设置规范模式 + if termios.local_mode.contains(LocalMode::ICANON) { + ldata.icanon = true; + } + + // 设置回显 + if termios.local_mode.contains(LocalMode::ECHO) { + ldata.echo = true; + } + + if termios.input_mode.contains(InputMode::ISTRIP) + || termios.input_mode.contains(InputMode::IUCLC) + || termios.input_mode.contains(InputMode::IGNCR) + || termios.input_mode.contains(InputMode::IXON) + || termios.local_mode.contains(LocalMode::ISIG) + || termios.local_mode.contains(LocalMode::ECHO) + || termios.input_mode.contains(InputMode::PARMRK) + { + // 非原模式 + + ldata.char_map.set_all(false); + + // 忽略回车符或者将回车映射为换行符 + if termios.input_mode.contains(InputMode::IGNCR) + || termios.input_mode.contains(InputMode::ICRNL) + { + ldata.char_map.set('\r' as usize, true); + } + + // 将换行映射为回车 + if termios.input_mode.contains(InputMode::INLCR) { + ldata.char_map.set('\n' as usize, true); + } + + // 规范模式 + if termios.local_mode.contains(LocalMode::ICANON) { + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VERASE] as usize, true); + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VKILL] as usize, true); + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VEOF] as usize, true); + ldata.char_map.set('\n' as usize, true); + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VEOL] as usize, true); + + if termios.local_mode.contains(LocalMode::IEXTEN) { + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VWERASE] as usize, true); + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VLNEXT] as usize, true); + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VEOL2] as usize, true); + if termios.local_mode.contains(LocalMode::ECHO) { + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VREPRINT] as usize, true); + } + } + } + + // 软件流控制 + if termios.input_mode.contains(InputMode::IXON) { + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VSTART] as usize, true); + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VSTOP] as usize, true); + } + + if termios.local_mode.contains(LocalMode::ISIG) { + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VINTR] as usize, true); + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VQUIT] as usize, true); + ldata + .char_map + .set(contorl_chars[ControlCharIndex::VSUSP] as usize, true); + } + + ldata + .char_map + .set(ControlCharIndex::DISABLE_CHAR as usize, true); + ldata.raw = false; + ldata.real_raw = false; + } else { + // 原模式或real_raw + ldata.raw = true; + + if termios.input_mode.contains(InputMode::IGNBRK) + || (!termios.input_mode.contains(InputMode::BRKINT) + && !termios.input_mode.contains(InputMode::PARMRK)) + && (termios.input_mode.contains(InputMode::IGNPAR) + || !termios.input_mode.contains(InputMode::INPCK)) + && (core + .driver() + .flags() + .contains(TtyDriverFlag::TTY_DRIVER_REAL_RAW)) + { + ldata.real_raw = true; + } else { + ldata.real_raw = false; + } + } + + // if !termios.input_mode.contains(InputMode::IXON) + // && old.is_some() + // && old.unwrap().input_mode.contains(InputMode::IXON) && ! + // {} + + core.read_wq().wakeup_all(); + core.write_wq().wakeup_all(); + Ok(()) + } + + fn poll(&self, _tty: Arc) -> Result<(), system_error::SystemError> { + todo!() + } + + fn hangup(&self, _tty: Arc) -> Result<(), system_error::SystemError> { + todo!() + } + + fn receive_buf( + &self, + tty: Arc, + buf: &[u8], + flags: Option<&[u8]>, + count: usize, + ) -> Result { + let mut ldata = self.disc_data(); + ldata.receive_buf_common(tty, buf, flags, count, false) + } + + fn receive_buf2( + &self, + tty: Arc, + buf: &[u8], + flags: Option<&[u8]>, + count: usize, + ) -> Result { + let mut ldata = self.disc_data(); + ldata.receive_buf_common(tty, buf, flags, count, true) + } +} diff --git a/kernel/src/driver/tty/tty_port.rs b/kernel/src/driver/tty/tty_port.rs new file mode 100644 index 00000000..a3e1e675 --- /dev/null +++ b/kernel/src/driver/tty/tty_port.rs @@ -0,0 +1,113 @@ +use core::fmt::Debug; + +use alloc::{ + sync::{Arc, Weak}, + vec::Vec, +}; +use kdepends::thingbuf::mpsc; +use system_error::SystemError; + +use crate::{ + driver::tty::virtual_terminal::MAX_NR_CONSOLES, + libs::spinlock::{SpinLock, SpinLockGuard}, +}; + +use super::tty_core::TtyCore; + +const TTY_PORT_BUFSIZE: usize = 4096; + +lazy_static! { + pub static ref TTY_PORTS: Vec> = { + let mut v: Vec> = Vec::with_capacity(MAX_NR_CONSOLES as usize); + for _ in 0..MAX_NR_CONSOLES as usize { + v.push(Arc::new(DefaultTtyPort::new())) + } + + v + }; +} + +#[allow(dead_code)] +#[derive(Debug)] +pub struct TtyPortData { + flags: i32, + iflags: TtyPortState, + sender: mpsc::Sender, + receiver: mpsc::Receiver, + tty: Weak, +} + +impl TtyPortData { + pub fn new() -> Self { + let (sender, receiver) = mpsc::channel::(TTY_PORT_BUFSIZE); + Self { + flags: 0, + iflags: TtyPortState::Initialized, + sender, + receiver, + tty: Weak::new(), + } + } + + pub fn tty(&self) -> Option> { + self.tty.upgrade() + } +} + +#[allow(dead_code)] +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum TtyPortState { + Initialized, + Suspended, + Active, + CtsFlow, + CheckCD, + KOPENED, +} + +pub trait TtyPort: Sync + Send + Debug { + fn port_data(&self) -> SpinLockGuard; + + /// 获取Port的状态 + fn state(&self) -> TtyPortState { + self.port_data().iflags + } + + /// 为port设置tty + fn setup_tty(&self, tty: Weak) { + self.port_data().tty = tty; + } + + /// 作为客户端的tty ports接收数据 + fn receive_buf(&self, buf: &[u8], _flags: &[u8], count: usize) -> Result { + let tty = self.port_data().tty.upgrade().unwrap(); + + let ld = tty.ldisc(); + + let ret = ld.receive_buf2(tty.clone(), buf, None, count); + if ret.is_err() && ret.clone().unwrap_err() == SystemError::ENOSYS { + return ld.receive_buf(tty, buf, None, count); + } + + ret + } +} + +#[derive(Debug)] +pub struct DefaultTtyPort { + port_data: SpinLock, +} + +impl DefaultTtyPort { + pub fn new() -> Self { + Self { + port_data: SpinLock::new(TtyPortData::new()), + } + } +} + +impl TtyPort for DefaultTtyPort { + fn port_data(&self) -> SpinLockGuard { + self.port_data.lock_irqsave() + } +} diff --git a/kernel/src/driver/tty/virtual_terminal/console_map.rs b/kernel/src/driver/tty/virtual_terminal/console_map.rs new file mode 100644 index 00000000..46f900b8 --- /dev/null +++ b/kernel/src/driver/tty/virtual_terminal/console_map.rs @@ -0,0 +1,135 @@ +/// Latin-1 字符集到 Unicode 的映射表。在这个表格中,每个位置都存储了相应 Latin-1 字符的 Unicode 编码。 +pub const LAT1_MAP: &'static [u16] = &[ + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, + 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x0080, 0x0081, 0x0082, 0x0083, + 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, + 0x009c, 0x009d, 0x009e, 0x009f, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, + 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, + 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, + 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, + 0x00fc, 0x00fd, 0x00fe, 0x00ff, +]; + +/// 将 VT100 图形字符映射到 Unicode 的映射表 +pub const GRAF_MAP: &'static [u16] = &[ + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, + 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f, + 0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0, + 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, 0x2591, 0x240b, 0x2518, 0x2510, + 0x250c, 0x2514, 0x253c, 0x23ba, 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, + 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f, 0x0080, 0x0081, 0x0082, 0x0083, + 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, + 0x009c, 0x009d, 0x009e, 0x009f, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, + 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, + 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, + 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, + 0x00fc, 0x00fd, 0x00fe, 0x00ff, +]; + +/// 将 IBM Codepage 437 字符集映射到 Unicode 的映射表 +pub const IBMPC_MAP: &'static [u16] = &[ + 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25d8, 0x25cb, 0x25d9, 0x2642, + 0x2640, 0x266a, 0x266b, 0x263c, 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8, + 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, + 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, + 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, 0x00c7, 0x00fc, 0x00e9, 0x00e2, + 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, + 0x00a3, 0x00a5, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, + 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, + 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, + 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, + 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, + 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, + 0x207f, 0x00b2, 0x25a0, 0x00a0, +]; + +/// 默认直接映射表 +pub const USER_MAP: &'static [u16] = &[ + 0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007, 0xf008, 0xf009, 0xf00a, 0xf00b, + 0xf00c, 0xf00d, 0xf00e, 0xf00f, 0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017, + 0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 0xf020, 0xf021, 0xf022, 0xf023, + 0xf024, 0xf025, 0xf026, 0xf027, 0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f, + 0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 0xf038, 0xf039, 0xf03a, 0xf03b, + 0xf03c, 0xf03d, 0xf03e, 0xf03f, 0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047, + 0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f, 0xf050, 0xf051, 0xf052, 0xf053, + 0xf054, 0xf055, 0xf056, 0xf057, 0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f, + 0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067, 0xf068, 0xf069, 0xf06a, 0xf06b, + 0xf06c, 0xf06d, 0xf06e, 0xf06f, 0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077, + 0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f, 0xf080, 0xf081, 0xf082, 0xf083, + 0xf084, 0xf085, 0xf086, 0xf087, 0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f, + 0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097, 0xf098, 0xf099, 0xf09a, 0xf09b, + 0xf09c, 0xf09d, 0xf09e, 0xf09f, 0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7, + 0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af, 0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, + 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7, 0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf, + 0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7, 0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, + 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf, 0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7, + 0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df, 0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, + 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7, 0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef, + 0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7, 0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, + 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff, +]; + +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum TranslationMapType { + Lat1Map, + GrafMap, + IbmpcMap, + UserMap, +} + +#[derive(Debug, Clone)] +pub struct TranslationMap { + pub map_type: TranslationMapType, + pub map: &'static [u16], +} + +impl TranslationMap { + pub const fn new(map_type: TranslationMapType) -> Self { + let map = match map_type { + TranslationMapType::Lat1Map => LAT1_MAP, + TranslationMapType::GrafMap => GRAF_MAP, + TranslationMapType::IbmpcMap => IBMPC_MAP, + TranslationMapType::UserMap => USER_MAP, + }; + + Self { map_type, map } + } + + pub fn translate(&self, c: u32) -> u16 { + self.map[c as usize] + } +} diff --git a/kernel/src/driver/tty/virtual_terminal/mod.rs b/kernel/src/driver/tty/virtual_terminal/mod.rs new file mode 100644 index 00000000..9f898329 --- /dev/null +++ b/kernel/src/driver/tty/virtual_terminal/mod.rs @@ -0,0 +1,303 @@ +use core::sync::atomic::Ordering; + +use alloc::{string::String, sync::Arc, vec::Vec}; +use system_error::SystemError; + +use crate::{ + driver::{ + base::device::{ + device_number::{DeviceNumber, Major}, + device_register, IdTable, + }, + video::fbdev::base::fbcon::framebuffer_console::BlittingFbConsole, + }, + filesystem::devfs::devfs_register, + libs::spinlock::SpinLock, +}; + +use self::virtual_console::{VirtualConsoleData, CURRENT_VCNUM}; + +use super::{ + console::ConsoleSwitch, + termios::{InputMode, TTY_STD_TERMIOS}, + tty_core::{TtyCore, TtyCoreData}, + tty_device::TtyDevice, + tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType, TtyOperation}, +}; + +pub mod console_map; +pub mod virtual_console; + +pub const MAX_NR_CONSOLES: u32 = 63; +pub const VC_MAXCOL: usize = 32767; +pub const VC_MAXROW: usize = 32767; + +pub const DEFAULT_RED: [u16; 16] = [ + 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, +]; + +pub const DEFAULT_GREEN: [u16; 16] = [ + 0x00, 0x00, 0xaa, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff, +]; + +pub const DEFAULT_BLUE: [u16; 16] = [ + 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, +]; + +pub const COLOR_TABLE: &'static [u8] = &[0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15]; + +lazy_static! { + pub static ref VIRT_CONSOLES: Vec>> = { + let mut v = Vec::with_capacity(MAX_NR_CONSOLES as usize); + for i in 0..MAX_NR_CONSOLES as usize { + v.push(Arc::new(SpinLock::new(VirtualConsoleData::new(i)))); + } + + v + }; +} + +#[derive(Debug, Clone, Copy, Default)] +pub struct Color { + pub red: u16, + pub green: u16, + pub blue: u16, + pub transp: u16, +} + +impl Color { + pub fn from_256(col: u32) -> Self { + let mut color = Self::default(); + if col < 8 { + color.red = if col & 1 != 0 { 0xaa } else { 0x00 }; + color.green = if col & 2 != 0 { 0xaa } else { 0x00 }; + color.blue = if col & 4 != 0 { 0xaa } else { 0x00 }; + } else if col < 16 { + color.red = if col & 1 != 0 { 0xff } else { 0x55 }; + color.green = if col & 2 != 0 { 0xff } else { 0x55 }; + color.blue = if col & 4 != 0 { 0xff } else { 0x55 }; + } else if col < 232 { + color.red = ((col - 16) / 36 * 85 / 2) as u16; + color.green = ((col - 16) / 6 % 6 * 85 / 2) as u16; + color.blue = ((col - 16) % 6 * 85 / 2) as u16; + } else { + let col = (col * 10 - 2312) as u16; + color.red = col; + color.green = col; + color.blue = col; + } + + color + } +} + +#[derive(Debug)] +pub struct TtyConsoleDriverInner { + console: Arc, +} + +unsafe impl Sync for TtyConsoleDriverInner {} + +impl TtyConsoleDriverInner { + pub fn new() -> Result { + Ok(Self { + console: Arc::new(BlittingFbConsole::new()?), + }) + } +} + +impl TtyOperation for TtyConsoleDriverInner { + fn install(&self, _driver: Arc, tty: Arc) -> Result<(), SystemError> { + let tty_core = tty.core(); + let mut vc_data = VIRT_CONSOLES[tty_core.index()].lock(); + + self.console.con_init(&mut vc_data, true)?; + if vc_data.complement_mask == 0 { + vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 }; + } + vc_data.s_complement_mask = vc_data.complement_mask; + // vc_data.bytes_per_row = vc_data.cols << 1; + vc_data.index = tty_core.index(); + vc_data.bottom = vc_data.rows; + vc_data.set_driver_funcs(Arc::downgrade( + &(self.console.clone() as Arc), + )); + + // todo: unicode字符集处理? + + if vc_data.cols > VC_MAXCOL || vc_data.rows > VC_MAXROW { + return Err(SystemError::EINVAL); + } + + vc_data.init(None, None, true); + vc_data.update_attr(); + + let window_size = tty_core.window_size_upgradeable(); + if window_size.col == 0 && window_size.row == 0 { + let mut window_size = window_size.upgrade(); + window_size.col = vc_data.cols as u16; + window_size.row = vc_data.rows as u16; + } + + if vc_data.utf { + tty_core.termios_write().input_mode.insert(InputMode::IUTF8); + } else { + tty_core.termios_write().input_mode.remove(InputMode::IUTF8); + } + + // 加入sysfs? + + Ok(()) + } + + fn open(&self, _tty: &TtyCoreData) -> Result<(), SystemError> { + Ok(()) + } + + fn write_room(&self, _tty: &TtyCoreData) -> usize { + 32768 + } + + /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/vt/vt.c#2894 + fn write(&self, tty: &TtyCoreData, buf: &[u8], mut nr: usize) -> Result { + // 关闭中断 + let mut vc_data = tty.vc_data_irqsave(); + + let mut offset = 0; + + // 这个参数是用来扫描unicode字符的,但是这部分目前未完成,先写着 + let mut rescan = false; + let mut ch: u32 = 0; + + let mut draw = DrawRegion::default(); + + // 首先隐藏光标再写 + vc_data.hide_cursor(); + + while nr != 0 { + if !rescan { + ch = buf[offset] as u32; + offset += 1; + nr -= 1; + } + + let (tc, rescan_last) = vc_data.translate(&mut ch); + if tc.is_none() { + // 表示未转换完成 + continue; + } + + let tc = tc.unwrap(); + rescan = rescan_last; + + if vc_data.is_control(tc, ch) { + vc_data.flush(&mut draw); + vc_data.do_control(ch); + continue; + } + + if !vc_data.console_write_normal(tc, ch, &mut draw) { + continue; + } + } + + vc_data.flush(&mut draw); + + // TODO: notify update + return Ok(offset); + } + + fn flush_chars(&self, tty: &TtyCoreData) { + let mut vc_data = tty.vc_data_irqsave(); + vc_data.set_cursor(); + } + + fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> { + self.write(tty, &[ch], 1)?; + Ok(()) + } + + fn ioctl(&self, _tty: Arc, _cmd: u32, _arg: usize) -> Result<(), SystemError> { + // TODO + Err(SystemError::ENOIOCTLCMD) + } +} + +#[derive(Debug, Clone)] +pub struct VtModeData { + mode: VtMode, + /// 释放请求时触发的信号 + relsig: u16, + /// 获取请求时触发的信号 + acqsig: u16, +} + +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum VtMode { + /// 自动切换模式,即在请求输入时自动切换到终端 + Auto, + /// 手动切换模式,需要通过 ioctl 请求切换到终端 + Process, + /// 等待终端确认,即在切换到终端时等待终端的确认信号 + Ackacq, +} + +/// 用于给vc确定要写入的buf位置 +#[derive(Debug, Default)] +pub struct DrawRegion { + /// 偏移量 + pub offset: usize, + /// 写入数量 + pub size: usize, + pub x: Option, +} + +// 初始化虚拟终端 +#[inline(never)] +pub fn vty_init() -> Result<(), SystemError> { + // 注册虚拟终端设备并将虚拟终端设备加入到文件系统 + let vc0 = TtyDevice::new( + "vc0", + IdTable::new( + String::from("vc0"), + Some(DeviceNumber::new(Major::TTY_MAJOR, 0)), + ), + ); + // 注册tty设备 + // CharDevOps::cdev_add( + // vc0.clone() as Arc, + // IdTable::new( + // String::from("vc0"), + // Some(DeviceNumber::new(Major::TTY_MAJOR, 0)), + // ), + // 1, + // )?; + + // CharDevOps::register_chardev_region(DeviceNumber::new(Major::TTY_MAJOR, 0), 1, "/dev/vc/0")?; + device_register(vc0.clone())?; + devfs_register("vc0", vc0)?; + + // vcs_init? + + let console_driver = TtyDriver::new( + MAX_NR_CONSOLES, + "tty", + 1, + Major::TTY_MAJOR, + 0, + TtyDriverType::Console, + TTY_STD_TERMIOS.clone(), + Arc::new(TtyConsoleDriverInner::new()?), + ); + + TtyDriverManager::tty_register_driver(console_driver)?; + + CURRENT_VCNUM.store(0, Ordering::SeqCst); + + // 初始化键盘? + + // TODO: 为vc + + Ok(()) +} diff --git a/kernel/src/driver/tty/virtual_terminal/virtual_console.rs b/kernel/src/driver/tty/virtual_terminal/virtual_console.rs new file mode 100644 index 00000000..7812cbbc --- /dev/null +++ b/kernel/src/driver/tty/virtual_terminal/virtual_console.rs @@ -0,0 +1,2015 @@ +use core::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; + +use alloc::{ + sync::{Arc, Weak}, + vec::Vec, +}; +use bitmap::{traits::BitMapOps, StaticBitmap}; + +use crate::{ + driver::tty::{console::ConsoleSwitch, ConsoleFont, KDMode}, + libs::{font::FontDesc, rwlock::RwLock}, + process::Pid, +}; + +use super::{ + console_map::{TranslationMap, TranslationMapType}, + Color, DrawRegion, VtMode, VtModeData, COLOR_TABLE, DEFAULT_BLUE, DEFAULT_GREEN, DEFAULT_RED, +}; + +pub(super) const NPAR: usize = 16; + +lazy_static! { + /// 是否已经添加了软光标 + pub(super) static ref SOFTCURSOR_ORIGINAL: RwLock> = RwLock::new(None); + + pub static ref CURRENT_VCNUM: AtomicIsize = AtomicIsize::new(-1); + + pub static ref CONSOLE_BLANKED: AtomicBool = AtomicBool::new(false); +} + +/// ## 虚拟控制台的信息 +#[derive(Debug, Clone)] +pub struct VirtualConsoleData { + pub num: usize, + pub state: VirtualConsoleInfo, + pub saved_state: VirtualConsoleInfo, + /// 最大列数 + pub cols: usize, + /// 最大行数 + pub rows: usize, + // /// 每行的字节数 + // pub bytes_per_row: usize, + /// 扫描行数 + pub scan_lines: usize, + /// 字符单元高度 + pub cell_height: u32, + + // /// 实际屏幕地址的开始 + // pub screen_base: VirtAddr, + // /// 实际屏幕的结束 + // pub scr_end: u64, + /// 可见窗口的开始 + pub visible_origin: usize, + /// 滚动窗口的顶部 + pub top: usize, + /// 滚动窗口的底部 + pub bottom: usize, + /// 当前读取位置 + pub pos: usize, + + /// 颜色集合 + pub palette: [Color; 16], + /// 默认颜色 + pub def_color: u8, + /// 下划线颜色 + pub underline_color: u32, + /// 斜体颜色 + pub italic_color: u32, + /// 半强度颜色 + pub half_color: u32, + + pub mode: KDMode, + pub vt_mode: VtModeData, + + /// 是否启用颜色 + pub color_mode: bool, + + // 字符 + pub hi_font_mask: u16, + pub font: ConsoleFont, + + pub erase_char: u16, + + pub complement_mask: u16, + pub s_complement_mask: u16, + + pub cursor_blink_ms: u16, + + pub pid: Option, + pub index: usize, + + pub vc_state: VirtualConsoleState, + + // 一些标志 + /// 指示是否显示 ASCII 字符小于 32 的控制字符(vc_disp_ctrl) + pub display_ctrl: bool, + /// 指示是否切换高位(meta)位。Meta 键是一个特殊的按键,用于扩展字符集。 + pub toggle_meta: bool, + /// 表示屏幕模式(vc_decscnm) + pub screen_mode: bool, + /// 指定光标移动的起始位置,是相对于屏幕的左上角还是相对于当前页的左上角(vc_decom) + pub origin_mode: bool, + /// 控制光标到达行末时是否自动换行(vc_decawm) + pub autowrap: bool, + /// 控制光标的可见性(vc_deccm) + pub cursor_visible: bool, + /// 光标相关 + pub cursor_type: VcCursor, + /// 控制插入或替换模式(vc_decim) + pub insert_mode: bool, + /// 表示一些私有模式或状态,通常由特定终端实现定义(vc_priv) + pub private: Vt102_OP, + /// 是否需要进行自动换行 + pub need_wrap: bool, + /// 控制鼠标事件的报告方式 + pub report_mouse: u8, + /// 指示终端是否使用 UTF-8 编码 + pub utf: bool, + /// UTF-8 编码的字符计数,表示还需要多少个字节才能够构建完成 + pub utf_count: u8, + /// UTF-8 编码的字符,表示正在构建的utf字符 + pub utf_char: u32, + /// 构建utf时需要的参数,表示目前接收了多少个字节的数据来构建utf字符 + pub npar: u32, + /// + pub par: [u32; NPAR], + + /// 字符转换表 用于将输入字符映射到特定的字符 + pub translate: TranslationMap, + + pub tab_stop: StaticBitmap<256>, + + pub attr: u8, + + /// vc缓冲区 + pub screen_buf: Vec, + + /// 对应的Console Driver funcs + driver_funcs: Option>, +} + +impl VirtualConsoleData { + pub fn new(num: usize) -> Self { + Self { + state: VirtualConsoleInfo::new(0, 0), + saved_state: Default::default(), + cols: Default::default(), + rows: Default::default(), + // bytes_per_row: Default::default(), + scan_lines: Default::default(), + cell_height: Default::default(), + // origin: Default::default(), + // scr_end: Default::default(), + visible_origin: Default::default(), + top: Default::default(), + bottom: Default::default(), + palette: [Default::default(); 16], + def_color: Default::default(), + underline_color: Default::default(), + italic_color: Default::default(), + half_color: Default::default(), + mode: Default::default(), + color_mode: Default::default(), + hi_font_mask: Default::default(), + erase_char: Default::default(), + complement_mask: Default::default(), + s_complement_mask: Default::default(), + cursor_blink_ms: 200, + pos: Default::default(), + vt_mode: VtModeData { + mode: VtMode::Auto, + relsig: 0, + acqsig: 0, + }, + pid: None, + index: 0, + font: Default::default(), + vc_state: VirtualConsoleState::ESnormal, + display_ctrl: Default::default(), + toggle_meta: Default::default(), + screen_mode: Default::default(), + origin_mode: Default::default(), + autowrap: Default::default(), + cursor_visible: Default::default(), + insert_mode: Default::default(), + private: Vt102_OP::EPecma, + need_wrap: Default::default(), + report_mouse: Default::default(), + utf: Default::default(), + utf_count: Default::default(), + utf_char: Default::default(), + translate: TranslationMap::new(TranslationMapType::Lat1Map), + npar: Default::default(), + tab_stop: StaticBitmap::new(), + par: [0; 16], + attr: Default::default(), + screen_buf: Default::default(), + driver_funcs: None, + cursor_type: VcCursor::empty(), + num, + } + } + + pub(super) fn init(&mut self, rows: Option, cols: Option, clear: bool) { + if rows.is_some() { + self.rows = rows.unwrap(); + } + if cols.is_some() { + self.cols = cols.unwrap(); + } + + self.pos = self.cols * self.state.y + self.state.x; + // self.bytes_per_row = self.cols << 1; + + self.def_color = 15; // white + self.italic_color = 2; // green + self.underline_color = 3; // cyan + self.half_color = 0x08; // grey + + self.reset(clear); + + self.screen_buf.resize(self.cols * self.rows, 0); + } + + pub fn should_update(&self) -> bool { + self.is_visible() && !CONSOLE_BLANKED.load(Ordering::SeqCst) + } + + pub fn is_visible(&self) -> bool { + let cur_vc = CURRENT_VCNUM.load(Ordering::SeqCst); + if cur_vc == -1 { + return false; + } + + cur_vc as usize == self.num + } + + fn driver_funcs(&self) -> Arc { + self.driver_funcs.as_ref().unwrap().upgrade().unwrap() + } + + pub(super) fn set_driver_funcs(&mut self, func: Weak) { + self.driver_funcs = Some(func); + } + + pub(super) fn reset(&mut self, do_clear: bool) { + self.mode = KDMode::KdText; + // unicode? + self.vt_mode.mode = VtMode::Auto; + self.vt_mode.acqsig = 0; + self.vt_mode.relsig = 0; + self.display_ctrl = false; + self.toggle_meta = false; + self.screen_mode = false; + self.origin_mode = false; + self.autowrap = true; + self.cursor_visible = true; + self.insert_mode = false; + self.need_wrap = false; + self.report_mouse = 0; + self.utf_count = 0; + self.translate = TranslationMap::new(TranslationMapType::Lat1Map); + self.utf = true; + self.pid = None; + self.vc_state = VirtualConsoleState::ESnormal; + self.reset_palette(); + self.cursor_type = VcCursor::CUR_UNDERLINE; + + self.default_attr(); + self.update_attr(); + + self.tab_stop.set_all(false); + + for i in (0..256).step_by(8) { + self.tab_stop.set(i, true); + } + + self.state.x = 0; + self.state.y = 0; + self.pos = 0; + + if do_clear { + self.csi_J(2); + } + } + + fn reset_palette(&mut self) { + for (idx, color) in self.palette.iter_mut().enumerate() { + color.red = DEFAULT_RED[idx]; + color.green = DEFAULT_GREEN[idx]; + color.blue = DEFAULT_BLUE[idx]; + } + + self.set_palette(); + } + + fn set_palette(&self) { + if self.mode != KDMode::KdGraphics { + // todo: 通知driver层的Console + let _ = self.driver_funcs().con_set_palette(self, COLOR_TABLE); + } + } + + /// ## 翻译字符,将字符转换为终端控制符 + /// ### 参数 + /// + /// ### c: 需要转换的字符 + /// + /// ### 返回值 + /// ### (转换后的字符:i32,是否需要更多的数据才能进行转换:bool) + pub(super) fn translate(&mut self, c: &mut u32) -> (Option, bool) { + if self.vc_state != VirtualConsoleState::ESnormal { + // 在控制字符状态下不需要翻译 + return (Some(*c), false); + } + if self.utf && !self.display_ctrl { + // utf模式并且不显示控制字符 + let (ret, rescan) = self.translate_unicode(*c); + if ret.is_some() { + *c = ret.unwrap(); + } + return (ret, rescan); + } + + return (Some(self.translate_ascii(*c)), false); + } + + /// 该数组包含每个字节序列长度变化的阈值 + /// 即如果由两个字节组成的unicode字符,则长度应该在UTF8_LENGTH_CHANGES[0] ~ UTF8_LENGTH_CHANGES[1]之间 + const UTF8_LENGTH_CHANGES: &'static [u32] = &[ + 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff, + ]; + + /// ## 翻译字符,将UTF-8 编码的字符转换为 Unicode 编码 + /// ### 参数 + /// + /// ### c: 需要转换的字符 + /// + /// ### 返回值 + /// ### (转换后的字符:i32,是否需要重新传入该字符:bool) + /// + /// !!! 注意,该函数返回true时,元组的第一个数据是无效数据(未转换完成) + fn translate_unicode(&mut self, c: u32) -> (Option, bool) { + // 收到的字符不是首个 + if (c & 0xc8) == 0x80 { + // 已经不需要继续的字符了,说明这个字符是非法的 + if self.utf_count == 0 { + return (Some(0xfffd), false); + } + + self.utf_char = (self.utf_char << 6) | (c & 0x3f); + self.npar += 1; + + self.utf_count -= 1; + if self.utf_count > 0 { + // 表示需要更多字节 + return (None, false); + } + + let c = self.utf_char; + + // 先检查一遍是否合格 + if c <= Self::UTF8_LENGTH_CHANGES[self.npar as usize - 1] + || c > Self::UTF8_LENGTH_CHANGES[self.npar as usize] + { + return (Some(0xfffd), false); + } + + return (Some(Self::sanitize_unicode(c)), false); + } + + // 接收到单个ASCII字符或者一个序列的首字符,且上次的未处理完,则上一个字符视为无效,则需要重新传入该字符处理 + if self.utf_count > 0 { + self.utf_count = 0; + return (Some(0xfffd), true); + } + + // ascii + if c <= 0x7f { + return (Some(c), false); + } + + // 第一个字节 + self.npar = 0; + if (c & 0xe0) == 0xc0 { + self.utf_count = 1; + self.utf_char = c & 0x1f; + } else if (c & 0xf0) == 0xe0 { + self.utf_count = 2; + self.utf_char = c & 0x0f; + } else if (c & 0xf8) == 0xf0 { + self.utf_count = 3; + self.utf_char = c & 0x07; + } else if (c & 0xfc) == 0xf8 { + self.utf_count = 4; + self.utf_char = c & 0x03; + } else if (c & 0xfe) == 0xfc { + self.utf_count = 5; + self.utf_char = c & 0x01; + } else { + /* 254 and 255 are invalid */ + return (Some(0xfffd), false); + } + + (None, false) + } + + /// ## 翻译字符,将字符转换为Ascii + fn translate_ascii(&self, c: u32) -> u32 { + let mut c = c; + if self.toggle_meta { + c |= 0x80; + } + + return self.translate.translate(c) as u32; + } + + /// ## 用于替换无效的 Unicode 代码点(code points)。 + /// Unicode 代码点的范围是从 U+0000 到 U+10FFFF, + /// 但是有一些特殊的代码点是无效的或者保留给特定用途的。 + /// 这个函数的主要目的是将无效的 Unicode 代码点替换为 U+FFFD,即 Unicode 替代字符。 + fn sanitize_unicode(c: u32) -> u32 { + if (c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff { + return 0xfffd; + } + return c; + } + + /// 用于表示小于 32 的字符中,哪些字符对应的位被设置为 1, + /// 表示这些字符会触发一些特殊的动作,比如光标移动等。 + /// 这些字符在 disp_ctrl 模式未开启时不应该被显示为图形符号 + const CTRL_ACTION: u32 = 0x0d00ff81; + /// 用于表示哪些控制字符是始终显示的,即便 disp_ctrl 模式未开启。 + /// 这些字符对于终端来说是必要的,显示它们是为了保证终端正常工作。 + /// 这些字符在 disp_ctrl 模式开启或关闭时都应该显示为控制字符。 + const CTRL_ALWAYS: u32 = 0x0800f501; + + /// ## 用于判断tc(终端字符)在当前VC下是不是需要显示的控制字符 + pub(super) fn is_control(&self, tc: u32, c: u32) -> bool { + // 当前vc状态机不在正常状态,即在接收特殊字符的状态,则是控制字符 + if self.vc_state != VirtualConsoleState::ESnormal { + return true; + } + + if tc == 0 { + return true; + } + + if c < 32 { + if self.display_ctrl { + // 查看在位图中是否有该字符 + return Self::CTRL_ALWAYS & (1 << c) != 0; + } else { + return self.utf || (Self::CTRL_ACTION & (1 << c) != 0); + } + } + + if c == 127 && !self.display_ctrl { + return true; + } + + if c == 128 + 27 { + return true; + } + + false + } + + pub(super) fn set_cursor(&mut self) { + if self.mode == KDMode::KdGraphics { + return; + } + + if self.cursor_visible { + // TODO: 处理选择 + self.add_softcursor(); + if self.cursor_type.cursor_size() != VcCursor::CUR_NONE { + self.driver_funcs().con_cursor(self, CursorOperation::Draw); + } + } else { + self.hide_cursor(); + } + } + + /// ## 添加软光标 + fn add_softcursor(&mut self) { + let mut i = self.screen_buf[self.pos] as u32; + let cursor_type = self.cursor_type; + + if !cursor_type.contains(VcCursor::CUR_SW) { + return; + } + + if SOFTCURSOR_ORIGINAL.read_irqsave().is_some() { + // 已经设置了软光标 + return; + } + + let mut soft_cursor_guard = SOFTCURSOR_ORIGINAL.write_irqsave(); + *soft_cursor_guard = Some(unsafe { VcCursor::from_bits_unchecked(i as u32) }); + + let soft_cursor = soft_cursor_guard.unwrap(); + + i |= cursor_type.cursor_set(); + i ^= cursor_type.cursor_change(); + if cursor_type.contains(VcCursor::CUR_ALWAYS_BG) + && ((soft_cursor.bits & VcCursor::CUR_BG.bits) == (i & VcCursor::CUR_BG.bits)) + { + i ^= VcCursor::CUR_BG.bits; + } + if cursor_type.contains(VcCursor::CUR_INVERT_FG_BG) + && ((i & VcCursor::CUR_FG.bits) == ((i & VcCursor::CUR_BG.bits) >> 4)) + { + i ^= VcCursor::CUR_FG.bits; + } + + self.screen_buf[self.pos] = i as u16; + + let _ = + self.driver_funcs() + .con_putc(&self, i as u16, self.state.y as u32, self.state.x as u32); + } + + pub fn hide_cursor(&mut self) { + // TODO: 处理选择 + + self.driver_funcs().con_cursor(self, CursorOperation::Erase); + self.hide_softcursor(); + } + + fn hide_softcursor(&mut self) { + let softcursor = SOFTCURSOR_ORIGINAL.upgradeable_read_irqsave(); + if softcursor.is_some() { + self.screen_buf[self.pos] = softcursor.unwrap().bits as u16; + let _ = self.driver_funcs().con_putc( + &self, + softcursor.unwrap().bits as u16, + self.state.y as u32, + self.state.x as u32, + ); + + *softcursor.upgrade() = None; + } + } + + fn gotoxay(&mut self, x: i32, y: i32) { + if self.origin_mode { + self.gotoxy(x, self.top as i32 + y); + } else { + self.gotoxy(x, y) + } + } + + // ## 将当前vc的光标移动到目标位置 + fn gotoxy(&mut self, x: i32, y: i32) { + if x < 0 { + self.state.x = 0; + } else { + if x as usize >= self.cols { + self.state.x = self.cols - 1; + } else { + self.state.x = x as usize; + } + } + + let max_y; + let min_y; + if self.origin_mode { + min_y = self.top; + max_y = self.bottom; + } else { + min_y = 0; + max_y = self.rows; + } + + if y < min_y as i32 { + self.state.y = min_y as usize; + } else if y >= max_y as i32 { + self.state.y = max_y as usize; + } else { + self.state.y = y as usize; + } + + self.pos = self.state.y * self.cols + (self.state.x << 1); + self.need_wrap = false; + } + + fn scroll(&mut self, dir: ScrollDir, mut nr: usize) { + // todo: uniscr_srceen + if self.top + nr >= self.bottom { + // 滚动超过一页,则按一页计算 + nr = self.bottom - self.top - 1; + } + + if nr < 1 { + return; + } + + if self + .driver_funcs() + .con_scroll(self, self.top, self.bottom, dir, nr) + { + // 如果成功 + return; + } + + // 调整screen_buf + let count = nr * self.cols; + if dir == ScrollDir::Up { + for i in self.screen_buf[0..count].iter_mut() { + *i = self.erase_char; + } + self.screen_buf.rotate_left(count); + } else if dir == ScrollDir::Down { + todo!(); + } + } + + /// ## 退格 + fn backspace(&mut self) { + if self.state.x > 0 { + self.pos -= 1; + self.state.x -= 1; + self.need_wrap = false; + + // TODO: notify + } + } + + /// ## 换行 + fn line_feed(&mut self) { + if self.state.y + 1 == self.bottom as usize { + self.scroll(ScrollDir::Up, 1); + } else if self.state.y < self.rows - 1 { + self.state.y += 1; + self.pos += self.cols; + } + + self.need_wrap = false; + // TODO: Notify write + } + + /// ## 回车 + fn carriage_return(&mut self) { + // 写入位置回退到该行最前 + self.pos -= self.state.x; + self.need_wrap = false; + self.state.x = 0; + } + + /// ## Del + fn delete(&mut self) { + // ignore + } + + /// ## 向上滚动虚拟终端的内容,或者将光标上移一行 + fn reverse_index(&mut self) { + if self.state.y == self.top as usize { + self.scroll(ScrollDir::Down, 1); + } else if self.state.y > 0 { + self.state.y -= 1; + self.pos -= self.cols; + } + self.need_wrap = false; + } + + /// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/vt/vt.c#restore_cur + fn restore_cursor(&mut self) { + self.saved_state = self.state.clone(); + + self.gotoxy(self.state.x as i32, self.state.y as i32); + + // TODO Gx_charset + + self.update_attr(); + self.need_wrap = false; + todo!() + } + + /// ## 设置当前vt的各项属性 + fn set_mode(&mut self, on_off: bool) { + for i in 0..self.npar as usize { + if self.private == Vt102_OP::EPdec { + match self.par[i] { + 1 => { + todo!("kbd todo"); + } + 3 => { + todo!("reisze todo"); + } + 5 => { + todo!("invert_screen todo"); + } + 6 => { + self.origin_mode = on_off; + if on_off { + self.gotoxy(0, self.top as i32); + } else { + self.gotoxy(0, 0); + } + } + 7 => { + self.autowrap = on_off; + } + 8 => { + todo!("kbd todo"); + } + 9 => { + todo!("report mouse todo"); + } + 25 => { + self.cursor_visible = on_off; + } + 1000 => { + todo!("report mouse todo"); + } + _ => {} + } + } else { + match self.par[i] { + 3 => { + self.display_ctrl = on_off; + } + 4 => { + self.insert_mode = on_off; + } + 20 => { + todo!("kbd todo"); + } + _ => {} + } + } + } + } + + fn do_getpars(&mut self, c: char) { + if c == ';' && self.npar < (NPAR - 1) as u32 { + self.npar += 1; + return; + } + + if c >= '0' && c <= '9' { + self.par[self.npar as usize] *= 10; + self.par[self.npar as usize] += (c as u8 - '0' as u8) as u32; + return; + } + + if c as u8 >= 0x20 && c as u8 <= 0x3f { + self.vc_state = VirtualConsoleState::EScsiignore; + return; + } + + self.vc_state = VirtualConsoleState::ESnormal; + + match c { + 'h' => { + if self.private <= Vt102_OP::EPdec { + self.set_mode(true); + } + return; + } + 'l' => { + if self.private <= Vt102_OP::EPdec { + self.set_mode(false); + } + return; + } + 'c' => { + if self.private == Vt102_OP::EPdec { + if self.par[0] != 0 { + self.cursor_type = + VcCursor::make_cursor(self.par[0], self.par[1], self.par[2]) + } else { + self.cursor_type = VcCursor::CUR_UNDERLINE; + } + return; + } + } + 'm' => { + if self.private == Vt102_OP::EPdec { + if self.par[0] != 0 { + self.complement_mask = (self.par[0] << 8 | self.par[1]) as u16; + } else { + self.complement_mask = self.s_complement_mask; + } + return; + } + } + 'n' => { + if self.private == Vt102_OP::EPecma { + if self.par[0] == 5 { + kwarn!("tty status report todo"); + } else if self.par[0] == 6 { + kwarn!("tty cursor report todo"); + } + } + return; + } + _ => {} + } + + if self.private != Vt102_OP::EPecma { + self.private = Vt102_OP::EPecma; + return; + } + + match c { + 'G' | '`' => { + if self.par[0] != 0 { + self.par[0] -= 1; + } + self.gotoxy(self.par[0] as i32, self.state.y as i32); + return; + } + 'A' => { + if self.par[0] == 0 { + self.par[0] += 1; + } + self.gotoxy( + self.state.x as i32, + (self.state.y - self.par[0] as usize) as i32, + ); + return; + } + 'B' | 'e' => { + if self.par[0] == 0 { + self.par[0] += 1; + } + self.gotoxy( + self.state.x as i32, + (self.state.y + self.par[0] as usize) as i32, + ); + return; + } + 'C' | 'a' => { + if self.par[0] == 0 { + self.par[0] += 1; + } + self.gotoxy( + (self.state.x + self.par[0] as usize) as i32, + self.state.y as i32, + ); + return; + } + 'D' => { + if self.par[0] == 0 { + self.par[0] += 1; + } + self.gotoxy( + (self.state.x - self.par[0] as usize) as i32, + self.state.y as i32, + ); + return; + } + 'E' => { + if self.par[0] == 0 { + self.par[0] += 1; + } + self.gotoxy(0, (self.state.y + self.par[0] as usize) as i32); + return; + } + 'F' => { + if self.par[0] == 0 { + self.par[0] += 1; + } + self.gotoxy(0, (self.state.y - self.par[0] as usize) as i32); + return; + } + 'd' => { + if self.par[0] != 0 { + self.par[0] -= 1; + } + self.gotoxay(self.state.x as i32, self.par[0] as i32); + return; + } + 'H' | 'f' => { + if self.par[0] != 0 { + self.par[0] -= 1; + } + if self.par[1] != 0 { + self.par[1] -= 1; + } + self.gotoxay(self.par[1] as i32, self.par[0] as i32); + return; + } + 'J' => { + self.csi_J(self.par[0]); + return; + } + 'K' => { + self.csi_K(self.par[0]); + return; + } + 'L' => { + todo!("csi_L todo"); + } + 'M' => { + todo!("csi_M todo"); + } + 'P' => { + todo!("csi_P todo"); + } + 'c' => { + if self.par[0] == 0 { + kwarn!("respone ID todo"); + } + return; + } + 'g' => { + if self.par[0] == 0 && self.state.x < 256 { + self.tab_stop.set(self.state.x as usize, true); + } else if self.par[0] == 3 { + self.tab_stop.set_all(false); + } + return; + } + 'm' => { + self.csi_m(); + return; + } + 'q' => { + if self.par[0] < 4 { + todo!("vt set led state todo"); + } + return; + } + 'r' => { + if self.par[0] == 0 { + self.par[0] += 1; + } + if self.par[1] == 0 { + self.par[1] = self.rows as u32; + } + if self.par[0] < self.par[1] && self.par[1] <= self.rows as u32 { + self.top = self.par[0] as usize - 1; + self.bottom = self.par[1] as usize; + self.gotoxay(0, 0); + } + return; + } + 's' => { + self.saved_state = self.state.clone(); + return; + } + 'u' => { + self.restore_cursor(); + return; + } + '@' => { + todo!("csi_at todo"); + } + ']' => { + todo!("set termial command todo"); + } + _ => {} + } + } + + /// ## 处理Control Sequence Introducer(控制序列引导符) m字符 + fn csi_m(&mut self) { + let mut i = 0; + loop { + if i > self.npar as usize { + break; + } + match self.par[i] { + 0 => { + // 关闭所有属性 + self.default_attr(); + } + + 1 => { + // 设置粗体 + self.state.intensity = VirtualConsoleIntensity::VciBold; + } + + 2 => { + // 设置半亮度(半明显 + self.state.intensity = VirtualConsoleIntensity::VciHalfBright; + } + + 3 => { + // 斜体 + self.state.italic = true; + } + + 4 | 21 => { + // 下划线 + + // 21是设置双下划线,但是不支持,就单下划线 + self.state.underline = true; + } + + 5 => { + // 设置闪烁 + self.state.blink = true; + } + + 7 => { + // 设置反显(前景色与背景色对调) + self.state.reverse = true; + } + + 10 => { + // 选择主要字体 + todo!() + } + + 11 => { + // 选择第一个替代字体 + todo!() + } + + 12 => { + // 选择第二个替代字体 + todo!() + } + + 22 => { + // 关闭粗体和半亮度,恢复正常亮度 + self.state.intensity = VirtualConsoleIntensity::VciNormal; + } + + 23 => { + // 关闭斜体 + self.state.italic = false; + } + + 24 => { + // 关闭下划线 + self.state.underline = false; + } + + 25 => { + // 关闭字符闪烁 + self.state.blink = false; + } + + 27 => { + // 关闭反显 + self.state.reverse = false; + } + + 38 => { + // 设置前景色 + let (idx, color) = self.t416_color(i); + i = idx; + if color.is_some() { + let color = color.unwrap(); + let mut max = color.red.max(color.green); + max = max.max(color.blue); + + let mut hue = 0; + if color.red > max / 2 { + hue |= 4; + } + if color.green > max / 2 { + hue |= 2; + } + if color.blue > max / 2 { + hue |= 1; + } + + if hue == 7 && max <= 0x55 { + hue = 0; + self.state.intensity = VirtualConsoleIntensity::VciBold; + } else if max > 0xaa { + self.state.intensity = VirtualConsoleIntensity::VciBold; + } else { + self.state.intensity = VirtualConsoleIntensity::VciNormal; + } + + self.state.color = (self.state.color & 0xf0) | hue; + } + } + + 48 => { + // 设置背景色 + let (idx, color) = self.t416_color(i); + i = idx; + if color.is_some() { + let color = color.unwrap(); + self.state.color = (self.state.color & 0x0f) + | ((color.red as u8 & 0x80) >> 1) + | ((color.green as u8 & 0x80) >> 2) + | ((color.blue as u8 & 0x80) >> 3); + } + } + + 39 => { + // 恢复默认前景色 + self.state.color = (self.def_color & 0x0f) | (self.state.color & 0xf0); + } + + 49 => { + // 恢复默认背景色 + self.state.color = (self.def_color & 0xf0) | (self.state.color & 0x0f); + } + + _ => { + if self.par[i] >= 90 && self.par[i] <= 107 { + if self.par[i] < 100 { + self.state.intensity = VirtualConsoleIntensity::VciBold; + } + self.par[i] -= 60; + } + + if self.par[i] >= 30 && self.par[i] <= 37 { + self.state.color = + COLOR_TABLE[self.par[i] as usize - 30] | self.state.color & 0xf0; + } else if self.par[i] >= 40 && self.par[i] <= 47 { + self.state.color = + (COLOR_TABLE[self.par[i] as usize - 40] << 4) | self.state.color & 0xf0; + } + } + } + + i += 1; + } + + self.update_attr(); + } + + /// ## 处理Control Sequence Introducer(控制序列引导符) J字符 + /// 该命令用于擦除终端显示区域的部分或全部内容。根据参数 vpar 的不同值,执行不同的擦除操作: + /// - vpar 为 0 时,擦除从光标位置到显示区域末尾的内容; + /// - vpar 为 1 时,擦除从显示区域起始位置到光标位置的内容; + /// - vpar 为 2 或 3 时,分别表示擦除整个显示区域的内容,其中参数 3 还会清除回滚缓冲区的内容。 + #[allow(non_snake_case)] + fn csi_J(&mut self, vpar: u32) { + let count; + let start; + + match vpar { + 0 => { + // 擦除从光标位置到显示区域末尾的内容 + count = self.screen_buf.len() - self.pos; + start = self.pos; + } + 1 => { + // 擦除从显示区域起始位置到光标位置的内容 + count = self.pos; + start = 0; + } + 2 => { + // 擦除整个显示区域的内容 + count = self.screen_buf.len(); + start = 0; + } + 3 => { + // 表示擦除整个显示区域的内容,还会清除回滚缓冲区的内容 + // TODO:当前未实现回滚缓冲 + count = self.screen_buf.len(); + start = 0; + } + _ => { + return; + } + } + + for i in self.screen_buf[start..(start + count)].iter_mut() { + *i = self.erase_char; + } + + if self.should_update() { + self.do_update_region(start, count) + } + + self.need_wrap = false; + } + + /// ## 处理Control Sequence Introducer(控制序列引导符) K字符 + /// 该命令用于擦除终端当前行的部分或全部内容。根据参数 vpar 的不同值,执行不同的擦除操作: + /// - vpar 为 0 时,擦除从光标位置到该行末尾的内容 + /// - vpar 为 1 时,擦除从该行起始位置到光标位置的内容 + /// - vpar 为 2 时,擦除整个行。 + #[allow(non_snake_case)] + fn csi_K(&mut self, vpar: u32) { + let count; + let start; + + match vpar { + 0 => { + // 擦除从光标位置到该行末尾的内容 + count = self.cols - self.state.x; + start = self.pos; + } + 1 => { + // 擦除从该行起始位置到光标位置的内容 + count = self.state.x + 1; + start = self.pos - self.state.x; + } + 2 => { + // 擦除整个行 + count = self.cols; + start = self.pos - self.state.x; + } + _ => { + return; + } + } + + for i in self.screen_buf[start..(start + count)].iter_mut() { + *i = self.erase_char; + } + + if self.should_update() { + self.do_update_region(start, count) + } + + self.need_wrap = false; + } + + fn t416_color(&mut self, mut idx: usize) -> (usize, Option) { + idx += 1; + if idx > self.npar as usize { + return (idx, None); + } + + if self.par[idx] == 5 && idx + 1 <= self.npar as usize { + // 256色 + idx += 1; + return (idx, Some(Color::from_256(self.par[idx]))); + } else if self.par[idx] == 2 && idx + 3 <= self.npar as usize { + // 24位 + let mut color = Color::default(); + color.red = self.par[idx + 1] as u16; + color.green = self.par[idx + 2] as u16; + color.blue = self.par[idx + 3] as u16; + idx += 3; + return (idx, Some(color)); + } else { + return (idx, None); + } + } + + /// ## 处理终端控制字符 + pub(super) fn do_control(&mut self, ch: u32) { + // 首先检查是否处于 ANSI 控制字符串状态 + if self.vc_state.is_ansi_control_string() && ch >= 8 && ch <= 13 { + return; + } + + match ch { + 0 => { + return; + } + 7 => { + // BEL + if self.vc_state.is_ansi_control_string() { + self.vc_state = VirtualConsoleState::ESnormal; + } + // TODO: 发出声音? + return; + } + 8 => { + // BS backspace + self.backspace(); + return; + } + 9 => { + // 水平制表符(Horizontal Tab) + self.pos -= self.state.x; + + let ret = self.tab_stop.next_index(self.state.x + 1); + + if ret.is_none() { + self.state.x = self.cols - 1; + } else { + self.state.x = ret.unwrap(); + } + + self.pos += self.state.x; + // TODO: notify + return; + } + 10 | 11 | 12 => { + // LD line feed + self.line_feed(); + // TODO: 检查键盘模式 + self.carriage_return(); + return; + } + 13 => { + // CR 回车符 + self.carriage_return(); + return; + } + 14 => { + todo!("Gx_charset todo!"); + } + 15 => { + todo!("Gx_charset todo!"); + } + 24 | 26 => { + self.vc_state = VirtualConsoleState::ESnormal; + return; + } + 27 => { + // esc + self.vc_state = VirtualConsoleState::ESesc; + return; + } + 127 => { + // delete + self.delete(); + return; + } + 155 => { + // '[' + self.vc_state = VirtualConsoleState::ESsquare; + return; + } + _ => {} + } + + match self.vc_state { + VirtualConsoleState::ESesc => { + self.vc_state = VirtualConsoleState::ESnormal; + match ch as u8 as char { + '[' => { + self.vc_state = VirtualConsoleState::ESsquare; + } + ']' => { + self.vc_state = VirtualConsoleState::ESnonstd; + } + '_' => { + self.vc_state = VirtualConsoleState::ESapc; + } + '^' => { + self.vc_state = VirtualConsoleState::ESpm; + } + '%' => { + self.vc_state = VirtualConsoleState::ESpercent; + } + 'E' => { + self.carriage_return(); + self.line_feed(); + } + 'M' => { + self.reverse_index(); + } + 'D' => { + self.line_feed(); + } + 'H' => { + if self.state.x < 256 { + self.tab_stop.set(self.state.x, true); + } + } + 'P' => { + self.vc_state = VirtualConsoleState::ESdcs; + } + 'Z' => { + todo!("Respond ID todo!"); + } + '7' => self.saved_state = self.state.clone(), + '8' => self.restore_cursor(), + '(' => { + self.vc_state = VirtualConsoleState::ESsetG0; + } + ')' => { + self.vc_state = VirtualConsoleState::ESsetG1; + } + '#' => { + self.vc_state = VirtualConsoleState::EShash; + } + 'c' => { + self.reset(true); + } + '>' => { + todo!("clr_kbd todo"); + } + '=' => { + todo!("set_kbd todo"); + } + _ => {} + } + } + VirtualConsoleState::ESsquare => { + for i in self.par.iter_mut() { + *i = 0; + } + self.vc_state = VirtualConsoleState::ESgetpars; + self.npar = 0; + let c = ch as u8 as char; + if c == '[' { + self.vc_state = VirtualConsoleState::ESfunckey; + return; + } + + match c { + '?' => { + self.private = Vt102_OP::EPdec; + return; + } + '>' => { + self.private = Vt102_OP::EPgt; + return; + } + '=' => { + self.private = Vt102_OP::EPeq; + return; + } + '<' => { + self.private = Vt102_OP::EPlt; + return; + } + _ => {} + } + + self.private = Vt102_OP::EPecma; + self.do_getpars(c); + } + VirtualConsoleState::ESgetpars => { + let c = ch as u8 as char; + self.do_getpars(c); + } + VirtualConsoleState::ESfunckey => { + self.vc_state = VirtualConsoleState::ESnormal; + return; + } + VirtualConsoleState::EShash => { + self.vc_state = VirtualConsoleState::ESnormal; + if ch as u8 as char == '8' { + self.erase_char = (self.erase_char & 0xff00) | 'E' as u16; + self.csi_J(2); + self.erase_char = (self.erase_char & 0xff00) | ' ' as u16; + self.do_update_region(0, self.screen_buf.len()); + } + return; + } + VirtualConsoleState::ESsetG0 => { + todo!("SetGx todo"); + } + VirtualConsoleState::ESsetG1 => { + todo!("SetGx todo"); + } + VirtualConsoleState::ESpercent => { + self.vc_state = VirtualConsoleState::ESnormal; + let c = ch as u8 as char; + match c { + '@' => { + self.utf = false; + return; + } + 'G' | '8' => { + self.utf = true; + return; + } + _ => {} + } + return; + } + VirtualConsoleState::EScsiignore => { + if ch >= 20 && ch <= 0x3f { + return; + } + self.vc_state = VirtualConsoleState::ESnormal; + return; + } + VirtualConsoleState::ESnonstd => { + let c = ch as u8 as char; + if c == 'P' { + for i in self.par.iter_mut() { + *i = 0; + } + self.npar = 0; + self.vc_state = VirtualConsoleState::ESpalette; + return; + } else if c == 'R' { + self.reset_palette(); + self.vc_state = VirtualConsoleState::ESnormal; + } else if c >= '0' && c <= '9' { + self.vc_state = VirtualConsoleState::ESosc; + } else { + self.vc_state = VirtualConsoleState::ESnormal; + } + } + VirtualConsoleState::ESpalette => { + let c = ch as u8 as char; + if c.is_digit(16) { + self.npar += 1; + self.par[self.npar as usize] = c.to_digit(16).unwrap(); + + if self.npar == 7 { + let mut i = self.par[0] as usize; + let mut j = 0; + self.palette[i].red = self.par[j] as u16; + j += 1; + self.palette[i].green = self.par[j] as u16; + j += 1; + self.palette[i].blue = self.par[j] as u16; + j += 1; + i += 1; + self.palette[i].red = self.par[j] as u16; + j += 1; + self.palette[i].green = self.par[j] as u16; + j += 1; + self.palette[i].blue = self.par[j] as u16; + self.set_palette(); + self.vc_state = VirtualConsoleState::ESnormal; + } + } + } + VirtualConsoleState::ESosc => {} + VirtualConsoleState::ESapc => {} + VirtualConsoleState::ESpm => {} + VirtualConsoleState::ESdcs => {} + VirtualConsoleState::ESnormal => {} + } + } + + pub(super) fn console_write_normal( + &mut self, + mut tc: u32, + c: u32, + draw: &mut DrawRegion, + ) -> bool { + let mut attr = self.attr; + let himask = self.hi_font_mask; + let charmask = if himask == 0 { 0xff } else { 0x1ff }; + let mut width = 1; + // 表示需不需要反转 + let mut invert = false; + if self.utf && !self.display_ctrl { + if FontDesc::is_double_width(c) { + width = 2; + } + } + + let tmp = self.unicode_to_index(tc); + if tmp & (!charmask as i32) != 0 { + if tmp == -1 || tmp == -2 { + return false; + } + + // 未找到 + if (!self.utf || self.display_ctrl || c < 128) && c & !charmask == 0 { + tc = c; + } else { + let tmp = self.unicode_to_index(0xfffd); + if tmp < 0 { + invert = true; + let tmp = self.unicode_to_index('?' as u32); + if tmp < 0 { + tc = '?' as u32; + } else { + tc = tmp as u32; + } + + attr = self.invert_attr(); + self.flush(draw); + } + } + } + + loop { + if self.need_wrap || self.insert_mode { + self.flush(draw); + } + if self.need_wrap { + self.carriage_return(); + self.line_feed(); + } + + if self.insert_mode { + self.insert_char(1); + } + + // TODO: 处理unicode screen buf + + if himask != 0 { + tc = ((if tc & 0x100 != 0 { himask as u32 } else { 0 }) | (tc & 0xff)) as u32; + } + + tc |= ((attr as u32) << 8) & (!himask as u32); + + // kwarn!( + // "ch {} pos {} x {} y {} cols {}", + // c as u8 as char, + // self.pos, + // self.state.x, + // self.state.y, + // self.cols, + // ); + self.screen_buf[self.pos] = tc as u16; + + if draw.x.is_none() { + // 设置draw参数 + draw.x = Some(self.state.x as u32); + draw.offset = self.pos; + } + + if self.state.x == self.cols - 1 { + // 需要换行? + self.need_wrap = self.autowrap; + draw.size += 1; + } else { + self.state.x += 1; + self.pos += 1; + draw.size += 1; + } + + width -= 1; + if width == 0 { + break; + } + let tmp = self.unicode_to_index(' ' as u32); + tc = if tmp < 0 { ' ' as u32 } else { tmp as u32 }; + } + + if invert { + self.flush(draw); + } + + true + } + + /// ## 当前vc插入nr个字符 + fn insert_char(&mut self, nr: usize) { + // TODO: 管理unicode屏幕信息 + + let pos = self.pos; + // 把当前位置以后得字符向后移动nr*2位 + self.screen_buf[pos..].rotate_right(nr * 2); + + // 把空出来的位置用erase_char填充 + for c in &mut self.screen_buf[pos..(pos + nr * 2)] { + *c = self.erase_char + } + + self.need_wrap = false; + + // 更新本行后面部分 + self.do_update_region(self.pos, self.cols - self.state.x); + } + + /// ## 更新虚拟控制台指定区域的显示 + fn do_update_region(&self, mut start: usize, mut count: usize) { + let ret = self.driver_funcs().con_getxy(self, start); + let (mut x, mut y) = if ret.is_err() { + let offset = start / 2; + (offset % self.cols, offset / self.cols) + } else { + let (tmp_start, tmp_x, tmp_y) = ret.unwrap(); + start = tmp_start; + (tmp_x, tmp_y) + }; + + loop { + // 记录当前字符的属性 + let mut attr = self.screen_buf[start] & 0xff00; + let mut startx = x; + let mut size = 0; + + while count != 0 && x < self.cols { + // 检查属性是否变化,如果属性变了,则将前一个字符先输出 + if attr != (self.screen_buf[start] & 0xff00) { + if size > 0 { + let _ = self.driver_funcs().con_putcs( + self, + &self.screen_buf[start..], + size, + y as u32, + startx as u32, + ); + startx = x; + start += size; + size = 0; + attr = self.screen_buf[start] & 0xff00; + } + } + size += 1; + x += 1; + count -= 1; + } + + if size > 0 { + let _ = self.driver_funcs().con_putcs( + self, + &self.screen_buf[start..], + size, + y as u32, + startx as u32, + ); + } + if count == 0 { + break; + } + + // 一行 + x = 0; + y += 1; + + let ret = self.driver_funcs().con_getxy(self, start); + if ret.is_ok() { + start = ret.unwrap().0; + } + } + } + + const UNI_DIRECT_MAKS: u32 = 0x01ff; + const UNI_DIRECT_BASE: u32 = 0xf000; + /// ## unicode字符转对应的坐标,暂时这样写,还没有适配unicode + /// 这里是糊代码的,后面重写 + fn unicode_to_index(&self, ch: u32) -> i32 { + if ch > 0xfff { + // 未找到 + return -4; + } else if ch < 0x20 { + // 不可打印 + return -1; + } else if ch == 0xfeff || (ch >= 0x200b && ch <= 0x200f) { + // 零长空格 + return -2; + } else if (ch & !Self::UNI_DIRECT_MAKS) == Self::UNI_DIRECT_BASE { + return (ch & Self::UNI_DIRECT_MAKS) as i32; + } + + // TODO: 暂时这样写,表示不支持 + return -3; + } + + fn invert_attr(&self) -> u8 { + if !self.color_mode { + return self.attr ^ 0x08; + } + + if self.hi_font_mask == 0x100 { + return (self.attr & 0x11) | ((self.attr & 0xe0) >> 4) | ((self.attr & 0x0e) << 4); + } + + return (self.attr & 0x88) | ((self.attr & 0x70) >> 4) | ((self.attr & 0x07) << 4); + } + + pub(super) fn flush(&self, draw: &mut DrawRegion) { + if draw.x.is_none() { + return; + } + + let _ = self.driver_funcs().con_putcs( + self, + &self.screen_buf[draw.offset..draw.offset + draw.size], + draw.size, + self.state.y as u32, + draw.x.unwrap() as u32, + ); + + draw.x = None; + draw.size = 0; + } + + fn build_attr( + &self, + color: u8, + intensity: VirtualConsoleIntensity, + blink: bool, + underline: bool, + reverse: bool, + italic: bool, + ) -> u8 { + let ret = self + .driver_funcs() + .con_build_attr(self, color, intensity, blink, underline, reverse, italic); + + if ret.is_ok() { + return ret.unwrap(); + } + + let mut ret = color; + + if !self.color_mode { + return intensity as u8 + | (italic as u8) << 1 + | (underline as u8) << 2 + | (reverse as u8) << 3 + | (blink as u8) << 7; + } + + if italic { + ret = (ret & 0xf0) | self.italic_color as u8; + } else if underline { + ret = (ret & 0xf0) | self.underline_color as u8; + } else if intensity == VirtualConsoleIntensity::VciHalfBright { + ret = (ret & 0xf0) | self.half_color as u8; + } + + if reverse { + ret = (ret & 0x88) | (((ret >> 4) | (ret << 4)) & 0x77); + } + + if blink { + ret ^= 0x80; + } + + if intensity == VirtualConsoleIntensity::VciBold { + ret ^= 0x08; + } + + if self.hi_font_mask == 0x100 { + ret <<= 1; + } + + ret + } + + pub(super) fn update_attr(&mut self) { + self.attr = self.build_attr( + self.state.color, + self.state.intensity, + self.state.blink, + self.state.underline, + self.state.reverse ^ self.screen_mode, + self.state.italic, + ); + + self.erase_char = ' ' as u16 + | ((self.build_attr( + self.state.color, + VirtualConsoleIntensity::VciNormal, + self.state.blink, + false, + self.screen_mode, + false, + ) as u16) + << 8); + } + + fn default_attr(&mut self) { + self.state.intensity = VirtualConsoleIntensity::VciNormal; + self.state.italic = false; + self.state.underline = false; + self.state.reverse = false; + self.state.blink = false; + self.state.color = self.def_color; + } +} + +/// ## 虚拟控制台的状态信息 +#[derive(Debug, Default, Clone)] +pub struct VirtualConsoleInfo { + // x,y表示光标坐标 + pub x: usize, + pub y: usize, + pub color: u8, + + /// 表示字符的强度 + intensity: VirtualConsoleIntensity, + /// 斜体 + italic: bool, + /// 下划线 + underline: bool, + /// 字符闪烁 + blink: bool, + /// 前景与背景色反转 + reverse: bool, +} + +impl VirtualConsoleInfo { + pub fn new(x: usize, y: usize) -> Self { + Self { + x, + y, + color: Default::default(), + intensity: Default::default(), + italic: Default::default(), + underline: Default::default(), + blink: Default::default(), + reverse: Default::default(), + } + } +} + +/// 字符强度 +#[derive(Debug, Clone, PartialEq, Copy)] +pub enum VirtualConsoleIntensity { + /// 暗淡 + VciHalfBright = 0, + /// 正常 + VciNormal = 1, + /// 粗体 + VciBold = 2, +} + +impl Default for VirtualConsoleIntensity { + fn default() -> Self { + Self::VciNormal + } +} + +/// ## 虚拟控制台的状态 +/// +/// 可以把VC的接收字符理解为一个状态机 +#[derive(Debug, PartialEq, Clone)] +pub enum VirtualConsoleState { + /// 正常状态 + ESnormal, + /// 收到了转义字符 \e,即"Escape"字符 + ESesc, + /// 收到了 "[" 字符,通常是 ANSI 控制序列的开始 + ESsquare, + /// 解析参数状态 + ESgetpars, + /// 功能键状态 + ESfunckey, + /// 收到了 "#" 字符 + EShash, + /// 设置 G0 字符集状态 + ESsetG0, + /// 设置 G1 字符集状态 + ESsetG1, + /// 收到了 "%" 字符 + ESpercent, + /// 忽略 ANSI 控制序列状态 + EScsiignore, + /// 非标准字符状态 + ESnonstd, + /// 调色板状态 + ESpalette, + /// Operating System Command (OSC) 状态 + ESosc, + /// Application Program Command (APC) 状态 + ESapc, + /// Privacy Message (PM) 状态 + ESpm, + /// Device Control String (DCS) 状态 + ESdcs, +} + +impl VirtualConsoleState { + pub fn is_ansi_control_string(&self) -> bool { + if *self == Self::ESosc + || *self == Self::ESapc + || *self == Self::ESpm + || *self == Self::ESdcs + { + return true; + } + + false + } +} + +#[derive(Debug, Clone, PartialEq, PartialOrd)] +#[allow(non_camel_case_types)] +pub enum Vt102_OP { + EPecma, + EPdec, + EPeq, + EPgt, + EPlt, +} + +bitflags! { + #[derive(Default)] + pub struct VcCursor: u32 { + /// 默认 + const CUR_DEF = 0; + /// 无光标 + const CUR_NONE = 1; + /// 下划线形式 + const CUR_UNDERLINE = 2; + /// 光标占据底部的三分之一 + const CUR_LOWER_THIRD = 3; + /// 光标占据底部的一半 + const CUR_LOWER_HALF = 4; + /// 光标占据底部的三分之二 + const CUR_TWO_THIRDS = 5; + /// 光标为块状(方块)形式 + const CUR_BLOCK = 6; + /// 光标属性,用于指示软件光标 + const CUR_SW = 0x000010; + /// 光标属性,用于指示光标是否始终在背景上显示 + const CUR_ALWAYS_BG = 0x000020; + /// 光标属性,用于指示前景和背景是否反转 + const CUR_INVERT_FG_BG = 0x000040; + /// 光标前景色属性,用于指定光标的前景色 + const CUR_FG = 0x000700; + /// 光标背景色属性,用于指定光标的背景色 + const CUR_BG = 0x007000; + } +} + +impl VcCursor { + pub fn make_cursor(size: u32, change: u32, set: u32) -> Self { + unsafe { Self::from_bits_unchecked(size | (change << 8) | (set << 16)) } + } + + pub fn cursor_size(&self) -> Self { + Self::from_bits_truncate(self.bits & 0x00000f) + } + + pub fn cursor_set(&self) -> u32 { + (self.bits & 0xff0000) >> 8 + } + + pub fn cursor_change(&self) -> u32 { + self.bits & 0x00ff00 + } +} + +#[derive(Debug, PartialEq)] +#[allow(dead_code)] +pub enum CursorOperation { + Draw, + Erase, + Move, +} + +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum ScrollDir { + Up, + Down, +} diff --git a/kernel/src/driver/tty/vt/mod.rs b/kernel/src/driver/tty/vt/mod.rs deleted file mode 100644 index dcbb36b0..00000000 --- a/kernel/src/driver/tty/vt/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Virtual terminal driver. -//! -//! (TODO) This driver is not implemented yet. - -/// The minimum number of virtual terminals. -#[allow(dead_code)] -pub const MIN_NR_CONSOLES: usize = 1; -/// The maximum number of virtual terminals. -#[allow(dead_code)] -pub const MAX_NR_CONSOLES: usize = 63; diff --git a/kernel/src/driver/video/fbdev/base/fbcmap.rs b/kernel/src/driver/video/fbdev/base/fbcmap.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/kernel/src/driver/video/fbdev/base/fbcmap.rs @@ -0,0 +1 @@ + diff --git a/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs b/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs new file mode 100644 index 00000000..744f6430 --- /dev/null +++ b/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs @@ -0,0 +1,787 @@ +use alloc::{sync::Arc, vec::Vec}; +use system_error::SystemError; + +use crate::{ + driver::{ + tty::{ + console::ConsoleSwitch, + virtual_terminal::{ + virtual_console::{CursorOperation, ScrollDir, VcCursor, VirtualConsoleData}, + Color, + }, + }, + video::fbdev::base::{ + CopyAreaData, FbCursor, FbCursorSetMode, FbImage, FbVisual, FillRectData, FillRectROP, + FrameBuffer, ScrollMode, FRAME_BUFFER_SET, + }, + }, + libs::{ + font::FontDesc, + spinlock::{SpinLock, SpinLockGuard}, + }, +}; + +use super::{FbConAttr, FrameBufferConsole, FrameBufferConsoleData}; + +#[derive(Debug)] +pub struct BlittingFbConsole { + fb: SpinLock>>, + fbcon_data: SpinLock, +} + +unsafe impl Send for BlittingFbConsole {} +unsafe impl Sync for BlittingFbConsole {} + +impl BlittingFbConsole { + pub fn new() -> Result { + Ok(Self { + fb: SpinLock::new(None), + fbcon_data: SpinLock::new(FrameBufferConsoleData::default()), + }) + } + + pub fn fb(&self) -> Arc { + self.fb.lock().clone().unwrap() + } + + pub fn get_color(&self, vc_data: &VirtualConsoleData, c: u16, is_fg: bool) -> u32 { + let fb_info = self.fb(); + let mut color = 0; + + let depth = fb_info.color_depth(); + + if depth != 1 { + if is_fg { + let fg_shift = if vc_data.hi_font_mask != 0 { 9 } else { 8 }; + color = (c as u32 >> fg_shift) & 0x0f + } else { + let bg_shift = if vc_data.hi_font_mask != 0 { 13 } else { 12 }; + color = (c as u32 >> bg_shift) & 0x0f + } + } + + match depth { + 1 => { + let col = self.mono_color(); + let fg; + let bg; + if fb_info.current_fb_fix().visual != FbVisual::Mono01 { + fg = col; + bg = 0; + } else { + fg = 0; + bg = col; + } + color = if is_fg { fg } else { bg }; + } + 2 => { + /* + 颜色深度为2,即16色, + 将16色的颜色值映射到4色的灰度, + 其中颜色0映射为黑色,颜色1到6映射为白色, + 颜色7到8映射为灰色,其他颜色映射为强烈的白色。 + */ + if color >= 1 && color <= 6 { + // 白色 + color = 2; + } else if color >= 7 && color <= 8 { + // 灰色 + color = 1; + } else { + // 强白 + color = 3; + } + } + 3 => { + /* + 颜色深度为3,即256色,仅保留颜色的低3位,即颜色 0 到 7 + */ + color &= 7; + } + _ => {} + } + color + } + + /// ## 计算单色调的函数 + pub fn mono_color(&self) -> u32 { + let fb_info = self.fb(); + let mut max_len = fb_info + .current_fb_var() + .green + .length + .max(fb_info.current_fb_var().red.length); + + max_len = max_len.max(fb_info.current_fb_var().blue.length); + + return (!(0xfff << max_len)) & 0xff; + } + + pub fn bit_put_string( + &self, + vc_data: &VirtualConsoleData, + buf: &[u16], + attr: FbConAttr, + cnt: u32, + cellsize: u32, + image: &mut FbImage, + ) { + let charmask = if vc_data.hi_font_mask != 0 { + 0x1ff + } else { + 0xff + }; + + let mut offset; + let image_line_byte = image.width as usize / 8; + + let byte_width = vc_data.font.width as usize / 8; + let font_height = vc_data.font.height as usize; + // let mut char_offset = 0; + for char_offset in 0..cnt as usize { + // 在字符表中的index + let ch = buf[char_offset] & charmask; + // 计算出在font表中的偏移量 + let font_offset = ch as usize * cellsize as usize; + let font_offset_end = font_offset + cellsize as usize; + // 设置image的data + + let src = &vc_data.font.data[font_offset..font_offset_end]; + let mut dst = Vec::new(); + dst.resize(src.len(), 0); + dst.copy_from_slice(src); + + if !attr.is_empty() { + attr.update_attr(&mut dst, src, vc_data) + } + + offset = char_offset * byte_width; + let mut dst_offset = 0; + for _ in 0..font_height { + let dst_offset_next = dst_offset + byte_width; + image.data[offset..offset + byte_width] + .copy_from_slice(&dst[dst_offset..dst_offset_next]); + + offset += image_line_byte; + dst_offset = dst_offset_next; + } + } + + self.fb().fb_image_blit(image); + } +} + +impl ConsoleSwitch for BlittingFbConsole { + fn con_init( + &self, + vc_data: &mut VirtualConsoleData, + init: bool, + ) -> Result<(), system_error::SystemError> { + let fb_set_guard = FRAME_BUFFER_SET.read(); + let fb = fb_set_guard.get(vc_data.index); + if fb.is_none() { + return Err(SystemError::EINVAL); + } + let fb = fb.unwrap(); + if fb.is_none() { + panic!( + "The Framebuffer with FbID {} has not been initialized yet.", + vc_data.index + ) + } + + let fb = fb.as_ref().unwrap().clone(); + + if init { + // 初始化字体 + let var = fb.current_fb_var(); + let font = FontDesc::get_default_font(var.xres, var.yres, 0, 0); + vc_data.font.data = font.data.to_vec(); + vc_data.font.width = font.width; + vc_data.font.height = font.height; + vc_data.font.count = font.char_count; + } else { + kwarn!("The frontend Framebuffer is not implemented"); + } + + vc_data.color_mode = fb.color_depth() != 1; + vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 }; + + if vc_data.font.count == 256 { + // ascii + vc_data.hi_font_mask = 0; + } else { + vc_data.hi_font_mask = 0x100; + if vc_data.color_mode { + vc_data.complement_mask <<= 1; + } + } + + // TODO: 考虑rotate + if init { + vc_data.cols = (fb.current_fb_var().xres / vc_data.font.width) as usize; + vc_data.rows = (fb.current_fb_var().yres / vc_data.font.height) as usize; + + vc_data.pos = vc_data.state.x + vc_data.state.y * vc_data.cols; + + let new_size = vc_data.cols * vc_data.rows; + vc_data.screen_buf.resize(new_size, 0); + } else { + unimplemented!("Resize is not supported at the moment!"); + } + + // 初始化fb + *self.fb.lock() = Some(fb); + + Ok(()) + } + + fn con_deinit(&self) -> Result<(), system_error::SystemError> { + todo!() + } + + fn con_clear( + &self, + vc_data: &mut VirtualConsoleData, + sy: usize, + sx: usize, + height: usize, + width: usize, + ) -> Result<(), system_error::SystemError> { + let fb_data = self.fbcon_data(); + + if height == 0 || width == 0 { + return Ok(()); + } + + let y_break = (fb_data.display.virt_rows - fb_data.display.yscroll) as usize; + if sy < y_break && sy + height - 1 >= y_break { + // 分两次clear + let b = y_break - sy; + let _ = self.clear( + &vc_data, + fb_data.display.real_y(sy as u32), + sx as u32, + b as u32, + width as u32, + ); + let _ = self.clear( + &vc_data, + fb_data.display.real_y((sy + b) as u32), + sx as u32, + (height - b) as u32, + width as u32, + ); + } else { + let _ = self.clear( + &vc_data, + fb_data.display.real_y(sy as u32), + sx as u32, + height as u32, + width as u32, + ); + } + + Ok(()) + } + + fn con_putc( + &self, + vc_data: &VirtualConsoleData, + ch: u16, + xpos: u32, + ypos: u32, + ) -> Result<(), system_error::SystemError> { + self.con_putcs(vc_data, &[ch], 1, ypos, xpos) + } + + fn con_putcs( + &self, + vc_data: &VirtualConsoleData, + buf: &[u16], + count: usize, + ypos: u32, + xpos: u32, + ) -> Result<(), SystemError> { + if count == 0 { + return Ok(()); + } + let fbcon_data = self.fbcon_data(); + let c = buf[0]; + self.put_string( + vc_data, + buf, + count as u32, + fbcon_data.display.real_y(ypos), + xpos, + self.get_color(vc_data, c, true), + self.get_color(vc_data, c, false), + ) + } + + fn con_getxy( + &self, + vc_data: &VirtualConsoleData, + pos: usize, + ) -> Result<(usize, usize, usize), SystemError> { + if pos < vc_data.screen_buf.len() { + let x = pos % vc_data.cols; + let y = pos / vc_data.cols; + let mut next_line_start = pos + (vc_data.cols - x); + if next_line_start >= vc_data.screen_buf.len() { + next_line_start = 0 + } + return Ok((next_line_start, x, y)); + } else { + return Ok((0, 0, 0)); + } + } + + fn con_cursor( + &self, + vc_data: &VirtualConsoleData, + op: crate::driver::tty::virtual_terminal::virtual_console::CursorOperation, + ) { + let mut fbcon_data = self.fbcon_data(); + + let c = vc_data.screen_buf[vc_data.pos]; + + if vc_data.cursor_type.contains(VcCursor::CUR_SW) { + // 取消硬光标Timer,但是现在没有硬光标,先写在这 + } else { + // 添加硬光标Timer + } + + fbcon_data.cursor_flash = op != CursorOperation::Erase; + + drop(fbcon_data); + + self.cursor( + vc_data, + op, + self.get_color(vc_data, c, true), + self.get_color(vc_data, c, false), + ); + } + + fn con_set_palette( + &self, + vc_data: &VirtualConsoleData, + color_table: &[u8], + ) -> Result<(), SystemError> { + let fb_info = self.fb(); + let depth = fb_info.color_depth(); + let mut palette = Vec::new(); + palette.resize(16, Color::default()); + if depth > 3 { + let vc_palette = &vc_data.palette; + for i in 0..16 { + let idx = color_table[i]; + let col = palette.get_mut(idx as usize).unwrap(); + col.red = (vc_palette[i].red << 8) | vc_palette[i].red; + col.green = (vc_palette[i].green << 8) | vc_palette[i].green; + col.blue = (vc_palette[i].blue << 8) | vc_palette[i].blue; + } + } else { + todo!() + } + + self.fb().set_color_map(palette)?; + + Ok(()) + } + + fn con_scroll( + &self, + vc_data: &mut VirtualConsoleData, + top: usize, + bottom: usize, + dir: crate::driver::tty::virtual_terminal::virtual_console::ScrollDir, + mut count: usize, + ) -> bool { + self.con_cursor(vc_data, CursorOperation::Erase); + + let fbcon_data = self.fbcon_data(); + let scroll_mode = fbcon_data.display.scroll_mode; + + drop(fbcon_data); + + match dir { + ScrollDir::Up => { + if count > vc_data.rows { + count = vc_data.rows; + } + + match scroll_mode { + ScrollMode::Move => { + let start = top * vc_data.cols; + let end = bottom * vc_data.cols; + vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols); + + let _ = self.bmove( + vc_data, + top as i32, + 0, + top as i32 - count as i32, + 0, + (bottom - top) as u32, + vc_data.cols as u32, + ); + + let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols); + + let offset = vc_data.cols * (bottom - count); + for i in + vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut() + { + *i = vc_data.erase_char; + } + + return true; + } + ScrollMode::PanMove => todo!(), + ScrollMode::WrapMove => todo!(), + ScrollMode::Redraw => { + let start = top * vc_data.cols; + let end = bottom * vc_data.cols; + vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols); + + let data = &vc_data.screen_buf[start..(bottom - count) * vc_data.cols]; + + for line in top..(bottom - count) { + let mut start = line * vc_data.cols; + let end = start + vc_data.cols; + let mut offset = start; + let mut attr = 1; + let mut x = 0; + while offset < end { + let c = data[offset]; + + if attr != c & 0xff00 { + // 属性变化,输出完上一个的并且更新属性 + attr = c & 0xff00; + + let count = offset - start; + let _ = self.con_putcs( + vc_data, + &data[start..offset], + count, + line as u32, + x, + ); + start = offset; + x += count as u32; + } + + offset += 1; + } + let _ = self.con_putcs( + vc_data, + &data[start..offset], + offset - start, + line as u32, + x, + ); + } + + let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols); + + let offset = vc_data.cols * (bottom - count); + for i in + vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut() + { + *i = vc_data.erase_char; + } + + return true; + } + ScrollMode::PanRedraw => todo!(), + } + } + ScrollDir::Down => { + if count > vc_data.rows { + count = vc_data.rows; + } + + match scroll_mode { + ScrollMode::Move => todo!(), + ScrollMode::PanMove => todo!(), + ScrollMode::WrapMove => todo!(), + ScrollMode::Redraw => { + // self.scroll_redraw( + // vc_data, + // bottom - 1, + // bottom - top - count, + // count * vc_data.cols, + // false, + // ); + + let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols); + + let offset = vc_data.cols * top; + for i in + vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut() + { + *i = vc_data.erase_char; + } + + return true; + } + ScrollMode::PanRedraw => todo!(), + } + } + } + } +} + +impl FrameBufferConsole for BlittingFbConsole { + fn bmove( + &self, + vc_data: &VirtualConsoleData, + sy: i32, + sx: i32, + dy: i32, + dx: i32, + height: u32, + width: u32, + ) -> Result<(), SystemError> { + let area = CopyAreaData::new( + dx * vc_data.font.width as i32, + dy * vc_data.font.height as i32, + width * vc_data.font.width, + height * vc_data.font.height, + sx * vc_data.font.width as i32, + sy * vc_data.font.height as i32, + ); + + self.fb().fb_copyarea(area) + } + + fn clear( + &self, + vc_data: &VirtualConsoleData, + sy: u32, + sx: u32, + height: u32, + width: u32, + ) -> Result<(), SystemError> { + let region = FillRectData::new( + sx * vc_data.font.width, + sy * vc_data.font.height, + width * vc_data.font.width, + height * vc_data.font.height, + self.get_color(vc_data, vc_data.erase_char, false), + FillRectROP::Copy, + ); + + self.fb().fb_fillrect(region)?; + + Ok(()) + } + + fn put_string( + &self, + vc_data: &VirtualConsoleData, + data: &[u16], + mut count: u32, + y: u32, + x: u32, + fg: u32, + bg: u32, + ) -> Result<(), SystemError> { + // 向上取整 + let width = (vc_data.font.width + 7) / 8; + let cellsize = width * vc_data.font.height; + let fb_info = self.fb(); + // 一次能输出的最大字数,避免帧缓冲区溢出 + let max_cnt = (fb_info.current_fb_var().xres * fb_info.current_fb_var().yres) / cellsize; + let attr = FbConAttr::get_attr(data[0], fb_info.color_depth()); + + let mut image = FbImage { + x: x * vc_data.font.width, + y: y * vc_data.font.height, + width: 0, + height: vc_data.font.height, + fg, + bg, + depth: 1, + data: Default::default(), + }; + + image.data.resize(cellsize as usize * count as usize, 0); + + while count > 0 { + let cnt = count.min(max_cnt); + + image.width = vc_data.font.width * cnt; + + self.bit_put_string(vc_data, data, attr, cnt, cellsize, &mut image); + + image.x += cnt * vc_data.font.width; + count -= cnt; + } + + Ok(()) + } + + fn fbcon_data(&self) -> SpinLockGuard { + self.fbcon_data.lock() + } + + fn cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32) { + let mut fbcon_data = self.fbcon_data(); + let fb_info = self.fb(); + let mut cursor = FbCursor::default(); + let charmask = if vc_data.hi_font_mask != 0 { + 0x1ff + } else { + 0xff + }; + + // 向上取整 + let w = (vc_data.font.width + 7) / 8; + let y = fbcon_data.display.real_y(vc_data.state.y as u32); + + let c = vc_data.screen_buf[vc_data.pos]; + let attr = FbConAttr::get_attr(c, fb_info.color_depth()); + let char_offset = (c as usize & charmask) * ((w * vc_data.font.height) as usize); + + if fbcon_data.cursor_state.image.data != &vc_data.font.data[char_offset..] + || fbcon_data.cursor_reset + { + fbcon_data.cursor_state.image.data = vc_data.font.data[char_offset..].to_vec(); + cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETIMAGE); + } + + if !attr.is_empty() { + fbcon_data + .cursor_data + .resize(w as usize * vc_data.font.height as usize, 0); + + attr.update_attr( + &mut fbcon_data.cursor_data, + &vc_data.font.data[char_offset..], + vc_data, + ); + } + + if fbcon_data.cursor_state.image.fg != fg + || fbcon_data.cursor_state.image.bg != bg + || fbcon_data.cursor_reset + { + fbcon_data.cursor_state.image.fg = fg; + fbcon_data.cursor_state.image.bg = bg; + cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETCMAP); + } + + if fbcon_data.cursor_state.image.x != (vc_data.font.width * vc_data.state.x as u32) + || fbcon_data.cursor_state.image.y != (vc_data.font.height * y) + || fbcon_data.cursor_reset + { + fbcon_data.cursor_state.image.x = vc_data.font.width * vc_data.state.x as u32; + fbcon_data.cursor_state.image.y = vc_data.font.height * y; + cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETPOS); + } + + if fbcon_data.cursor_state.image.height != vc_data.font.height + || fbcon_data.cursor_state.image.width != vc_data.font.width + || fbcon_data.cursor_reset + { + fbcon_data.cursor_state.image.height = vc_data.font.height; + fbcon_data.cursor_state.image.width = vc_data.font.width; + cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSIZE); + } + + if fbcon_data.cursor_state.hot_x > 0 + || fbcon_data.cursor_state.hot_y > 0 + || fbcon_data.cursor_reset + { + fbcon_data.cursor_state.hot_x = 0; + cursor.hot_y = 0; + cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETHOT); + } + + if cursor.set_mode.contains(FbCursorSetMode::FB_CUR_SETSIZE) + || vc_data.cursor_type != fbcon_data.display.cursor_shape + || fbcon_data.cursor_state.mask.is_empty() + || fbcon_data.cursor_reset + { + fbcon_data.display.cursor_shape = vc_data.cursor_type; + cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSHAPE); + + let cur_height; + match fbcon_data.display.cursor_shape.cursor_size() { + VcCursor::CUR_NONE => { + cur_height = 0; + } + VcCursor::CUR_UNDERLINE => { + if vc_data.font.height < 10 { + cur_height = 1; + } else { + cur_height = 2; + } + } + VcCursor::CUR_LOWER_THIRD => { + cur_height = vc_data.font.height / 3; + } + VcCursor::CUR_LOWER_HALF => { + cur_height = vc_data.font.height >> 1; + } + VcCursor::CUR_TWO_THIRDS => { + cur_height = (vc_data.font.height << 1) / 3; + } + _ => { + cur_height = vc_data.font.height; + } + } + + // 表示空白部分 + let mut size = (vc_data.font.height - cur_height) * w; + while size > 0 { + size -= 1; + fbcon_data.cursor_state.mask.push(0x00); + } + size = cur_height * w; + // 表示光标显示部分 + while size > 0 { + size -= 1; + fbcon_data.cursor_state.mask.push(0xff); + } + } + + match op { + CursorOperation::Erase => { + fbcon_data.cursor_state.enable = false; + } + _ => { + fbcon_data.cursor_state.enable = !vc_data.cursor_type.contains(VcCursor::CUR_SW); + } + } + + if !attr.is_empty() { + cursor.image.data = fbcon_data.cursor_data.clone(); + } else { + cursor.image.data = vc_data.font.data + [char_offset..char_offset + (w as usize * vc_data.font.height as usize)] + .to_vec(); + } + cursor.image.fg = fbcon_data.cursor_state.image.fg; + cursor.image.bg = fbcon_data.cursor_state.image.bg; + cursor.image.x = fbcon_data.cursor_state.image.x; + cursor.image.y = fbcon_data.cursor_state.image.y; + cursor.image.height = fbcon_data.cursor_state.image.height; + cursor.image.width = fbcon_data.cursor_state.image.width; + cursor.hot_x = fbcon_data.cursor_state.hot_x; + cursor.hot_y = fbcon_data.cursor_state.hot_y; + cursor.mask = fbcon_data.cursor_state.mask.clone(); + cursor.enable = fbcon_data.cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = true; + + if fb_info.fb_cursor(&cursor).is_err() { + let _ = fb_info.soft_cursor(cursor); + } + + fbcon_data.cursor_reset = false; + } +} diff --git a/kernel/src/driver/video/fbdev/base/fbcon.rs b/kernel/src/driver/video/fbdev/base/fbcon/mod.rs similarity index 64% rename from kernel/src/driver/video/fbdev/base/fbcon.rs rename to kernel/src/driver/video/fbdev/base/fbcon/mod.rs index 73ae422d..e9a16fc5 100644 --- a/kernel/src/driver/video/fbdev/base/fbcon.rs +++ b/kernel/src/driver/video/fbdev/base/fbcon/mod.rs @@ -1,15 +1,19 @@ use alloc::{ string::{String, ToString}, sync::{Arc, Weak}, + vec::Vec, }; use system_error::SystemError; use crate::{ - driver::base::{ - class::Class, - device::{bus::Bus, device_manager, driver::Driver, Device, DeviceType, IdTable}, - kobject::{KObjType, KObject, KObjectState, LockedKObjectState}, - kset::KSet, + driver::{ + base::{ + class::Class, + device::{bus::Bus, device_manager, driver::Driver, Device, DeviceType, IdTable}, + kobject::{KObjType, KObject, KObjectState, LockedKObjectState}, + kset::KSet, + }, + tty::virtual_terminal::virtual_console::{CursorOperation, VcCursor, VirtualConsoleData}, }, filesystem::{ kernfs::KernFSInode, @@ -18,11 +22,13 @@ use crate::{ }, libs::{ rwlock::{RwLockReadGuard, RwLockWriteGuard}, - spinlock::SpinLock, + spinlock::{SpinLock, SpinLockGuard}, }, }; -use super::fbmem::sys_class_graphics_instance; +use super::{fbmem::sys_class_graphics_instance, FbCursor, ScrollMode}; + +pub mod framebuffer_console; /// framebuffer console设备管理器实例 static mut FB_CONSOLE_MANAGER: Option = None; @@ -332,3 +338,166 @@ impl Attribute for AttrCursorBlink { todo!() } } + +#[derive(Debug, Default)] +pub struct FrameBufferConsoleData { + /// 光标闪烁间隔 + pub cursor_blink_jiffies: i64, + /// 是否刷新光标 + pub cursor_flash: bool, + /// + pub display: FbConsoleDisplay, + /// 光标状态 + pub cursor_state: FbCursor, + /// 重设光标? + pub cursor_reset: bool, + /// cursor 位图数据 + pub cursor_data: Vec, +} + +pub trait FrameBufferConsole { + fn fbcon_data(&self) -> SpinLockGuard; + + /// ## 将位块移动到目标位置 + /// 坐标均以字体为单位而不是pixel + /// ### 参数 + /// ### sy: 起始位置的y坐标 + /// ### sx: 起始位置的x坐标、 + /// ### dy: 目标位置的y坐标 + /// ### dx: 目标位置的x坐标 + /// ### height: 位图高度 + /// ### width: 位图宽度 + fn bmove( + &self, + vc_data: &VirtualConsoleData, + sy: i32, + sx: i32, + dy: i32, + dx: i32, + height: u32, + width: u32, + ) -> Result<(), SystemError>; + + /// ## 清除位图 + /// + /// ### 参数 + /// ### sy: 原位置的y坐标 + /// ### sx: 原位置的x坐标、 + /// ### height: 位图高度 + /// ### width: 位图宽度 + fn clear( + &self, + vc_data: &VirtualConsoleData, + sy: u32, + sx: u32, + height: u32, + width: u32, + ) -> Result<(), SystemError>; + + /// ## 显示字符串 + /// + /// ### 参数 + /// ### y: 起始位置y坐标 + /// ### x: 起始位置的x坐标、 + /// ### fg: 前景色 + /// ### bg: 背景色 + fn put_string( + &self, + vc_data: &VirtualConsoleData, + data: &[u16], + count: u32, + y: u32, + x: u32, + fg: u32, + bg: u32, + ) -> Result<(), SystemError>; + + fn cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32); +} + +/// 表示 framebuffer 控制台与低级帧缓冲设备之间接口的数据结构 +#[derive(Debug, Default)] +pub struct FbConsoleDisplay { + /// 硬件滚动的行数 + pub yscroll: u32, + /// 光标 + pub cursor_shape: VcCursor, + /// 滚动模式 + pub scroll_mode: ScrollMode, + virt_rows: u32, +} + +impl FbConsoleDisplay { + pub fn real_y(&self, mut ypos: u32) -> u32 { + let rows = self.virt_rows; + ypos += self.yscroll; + if ypos < rows { + return ypos; + } else { + return ypos - rows; + } + } +} + +bitflags! { + pub struct FbConAttr:u8 { + const UNDERLINE = 1; + const REVERSE = 2; + const BOLD = 4; + } +} + +impl FbConAttr { + pub fn get_attr(c: u16, color_depth: u32) -> Self { + let mut attr = Self::empty(); + if color_depth == 1 { + if Self::underline(c) { + attr.insert(Self::UNDERLINE); + } + if Self::reverse(c) { + attr.intersects(Self::REVERSE); + } + if Self::blod(c) { + attr.insert(Self::BOLD); + } + } + attr + } + + pub fn update_attr(&self, dst: &mut [u8], src: &[u8], vc_data: &VirtualConsoleData) { + let mut offset = if vc_data.font.height < 10 { 1 } else { 2 } as usize; + + let width = (vc_data.font.width + 7) / 8; + let cellsize = (vc_data.font.height * width) as usize; + + // 大于offset的部分就是下划线 + offset = cellsize - (offset * width as usize); + for i in 0..cellsize { + let mut c = src[i]; + if self.contains(Self::UNDERLINE) && i >= offset { + // 下划线 + c = 0xff; + } + if self.contains(Self::BOLD) { + c |= c >> 1; + } + if self.contains(Self::REVERSE) { + c = !c; + } + + dst[i] = c; + } + } + + pub fn underline(c: u16) -> bool { + c & 0x400 != 0 + } + + pub fn blod(c: u16) -> bool { + c & 0x200 != 0 + } + + pub fn reverse(c: u16) -> bool { + c & 0x800 != 0 + } +} diff --git a/kernel/src/driver/video/fbdev/base/mod.rs b/kernel/src/driver/video/fbdev/base/mod.rs index 29436e31..3d1ad818 100644 --- a/kernel/src/driver/video/fbdev/base/mod.rs +++ b/kernel/src/driver/video/fbdev/base/mod.rs @@ -1,13 +1,24 @@ -use alloc::{string::String, sync::Arc}; +use alloc::{string::String, sync::Arc, vec::Vec}; use system_error::SystemError; use crate::{ - driver::base::device::Device, + driver::{base::device::Device, tty::virtual_terminal::Color}, + init::boot_params, + libs::rwlock::RwLock, mm::{ucontext::LockedVMA, PhysAddr, VirtAddr}, }; use self::fbmem::{FbDevice, FrameBufferManager}; +const COLOR_TABLE_8: &'static [u32] = &[ + 0x00000000, 0xff000000, 0x00ff0000, 0xffff0000, 0x0000ff00, 0xff00ff00, 0x00ffff00, 0xffffff00, + 0x000000ff, 0xff0000ff, 0x00ff00ff, 0xffff00ff, 0x0000ffff, 0xff00ffff, 0x00ffffff, 0xffffffff, +]; + +const COLOR_TABLE_16: &'static [u32] = &[0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff]; + +const COLOR_TABLE_32: &'static [u32] = &[0x00000000, 0xffffffff]; + pub mod fbcon; pub mod fbmem; pub mod fbsysfs; @@ -16,6 +27,14 @@ pub mod modedb; // 帧缓冲区id int_like!(FbId, u32); +lazy_static! { + pub static ref FRAME_BUFFER_SET: RwLock>>> = { + let mut ret = Vec::new(); + ret.resize(FrameBufferManager::FB_MAX, None); + RwLock::new(ret) + }; +} + impl FbId { /// 帧缓冲区id的初始值(无效值) pub const INIT: Self = Self::new(u32::MAX); @@ -37,10 +56,240 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { /// 设置帧缓冲区的id fn set_fb_id(&self, id: FbId); + + /// 通用的软件图像绘画 + fn generic_imageblit(&self, image: &FbImage) { + let boot_param = boot_params().read(); + let x = image.x; + let y = image.y; + let byte_per_pixel = core::mem::size_of::() as u32; + let bit_per_pixel = self.current_fb_var().bits_per_pixel; + + // 计算图像在帧缓冲中的起始位 + let mut bitstart = (y * self.current_fb_fix().line_length * 8) + (x * bit_per_pixel); + let start_index = bitstart & (32 - 1); + let pitch_index = (self.current_fb_fix().line_length & (byte_per_pixel - 1)) * 8; + // 位转字节 + bitstart /= 8; + + // 对齐到像素字节大小 + bitstart &= !(byte_per_pixel - 1); + + let dst1 = boot_param.screen_info.lfb_virt_base; + if dst1.is_none() { + return; + } + let mut dst1 = dst1.unwrap(); + dst1 = dst1 + VirtAddr::new(bitstart as usize); + + let _ = self.fb_sync(); + + if image.depth == 1 { + let fg; + let bg; + if self.current_fb_fix().visual == FbVisual::TrueColor + || self.current_fb_fix().visual == FbVisual::DirectColor + { + let fb_info_data = self.framebuffer_info_data().read(); + fg = fb_info_data.pesudo_palette[image.fg as usize]; + bg = fb_info_data.pesudo_palette[image.bg as usize]; + } else { + fg = image.fg; + bg = image.bg; + } + + if 32 % bit_per_pixel == 0 + && start_index == 0 + && pitch_index == 0 + && image.width & (32 / bit_per_pixel - 1) == 0 + && bit_per_pixel >= 8 + && bit_per_pixel <= 32 + { + unsafe { self.fast_imageblit(image, dst1, fg, bg) } + } else { + self.slow_imageblit(image, dst1, fg, bg, start_index, pitch_index) + } + } else { + todo!("color image blit todo"); + } + } + + /// 优化的单色图像绘制函数 + /// + /// 仅当 bits_per_pixel 为 8、16 或 32 时才能使用。 + /// 要求 image->width 可以被像素或 dword (ppw) 整除。 + /// 要求 fix->line_length 可以被 4 整除。 + /// 扫描线的开始和结束都是 dword 对齐的。 + unsafe fn fast_imageblit(&self, image: &FbImage, mut dst1: VirtAddr, fg: u32, bg: u32) { + let bpp = self.current_fb_var().bits_per_pixel; + let mut fgx = fg; + let mut bgx = bg; + let ppw = 32 / bpp; + let spitch = (image.width + 7) / 8; + let tab: &[u32]; + let mut color_tab: [u32; 16] = [0; 16]; + + match bpp { + 8 => { + tab = COLOR_TABLE_8; + } + 16 => { + tab = COLOR_TABLE_16; + } + 32 => { + tab = COLOR_TABLE_32; + } + _ => { + return; + } + } + + for _ in (0..(ppw - 1)).rev() { + fgx <<= bpp; + bgx <<= bpp; + fgx |= fg; + bgx |= bg; + } + + let bitmask = (1 << ppw) - 1; + let eorx = fgx ^ bgx; + let k = image.width / ppw; + + for (idx, val) in tab.iter().enumerate() { + color_tab[idx] = (*val & eorx) ^ bgx; + } + + let mut dst; + let mut shift; + let mut src; + let mut offset = 0; + let mut j = 0; + for _ in (0..image.height).rev() { + dst = dst1.as_ptr::(); + shift = 8; + src = offset; + match ppw { + 4 => { + // 8bpp + j = k; + while j >= 2 { + *dst = color_tab[(image.data[src] as usize >> 4) & bitmask]; + dst = dst.add(1); + *dst = color_tab[(image.data[src] as usize >> 0) & bitmask]; + dst = dst.add(1); + j -= 2; + src += 1; + } + } + 2 => { + // 16bpp + j = k; + while j >= 4 { + *dst = color_tab[(image.data[src] as usize >> 6) & bitmask]; + dst = dst.add(1); + *dst = color_tab[(image.data[src] as usize >> 4) & bitmask]; + dst = dst.add(1); + *dst = color_tab[(image.data[src] as usize >> 2) & bitmask]; + dst = dst.add(1); + *dst = color_tab[(image.data[src] as usize >> 0) & bitmask]; + dst = dst.add(1); + src += 1; + j -= 4; + } + } + 1 => { + // 32 bpp + j = k; + while j >= 8 { + *dst = color_tab[(image.data[src] as usize >> 7) & bitmask]; + dst = dst.add(1); + *dst = color_tab[(image.data[src] as usize >> 6) & bitmask]; + dst = dst.add(1); + *dst = color_tab[(image.data[src] as usize >> 5) & bitmask]; + dst = dst.add(1); + *dst = color_tab[(image.data[src] as usize >> 4) & bitmask]; + dst = dst.add(1); + *dst = color_tab[(image.data[src] as usize >> 3) & bitmask]; + dst = dst.add(1); + *dst = color_tab[(image.data[src] as usize >> 2) & bitmask]; + dst = dst.add(1); + *dst = color_tab[(image.data[src] as usize >> 1) & bitmask]; + dst = dst.add(1); + *dst = color_tab[(image.data[src] as usize >> 0) & bitmask]; + dst = dst.add(1); + src += 1; + j -= 8; + } + } + _ => {} + } + + while j != 0 { + shift -= ppw; + *dst = color_tab[(image.data[src] as usize >> shift) & bitmask]; + dst = dst.add(1); + if shift == 0 { + shift = 8; + src += 1; + } + } + + dst1 += VirtAddr::new(self.current_fb_fix().line_length as usize); + offset += spitch as usize; + } + } + + fn slow_imageblit( + &self, + _image: &FbImage, + _dst1: VirtAddr, + _fg: u32, + _bg: u32, + _start_index: u32, + _pitch_index: u32, + ) { + todo!(); + // let bpp = self.current_fb_var().bits_per_pixel; + // let pitch = self.current_fb_fix().line_length; + // let null_bits = 32 - bpp; + // let spitch = (image.width + 7) / 8; + + // // TODO:这里是需要计算的,但是目前用不到,先直接写 + // let bswapmask = 0; + + // let dst2 = dst1; + + // // 一行一行画 + // for i in image.height..0 { + // let dst = dst1; + + // if start_index > 0 { + // let start_mask = !(!(0 as u32) << start_index); + // } + // } + } +} + +#[derive(Debug, Default)] +pub struct FrameBufferInfoData { + /// 颜色映射 + pub color_map: Vec, + /// 颜色映射表 + pub pesudo_palette: Vec, +} + +impl FrameBufferInfoData { + pub fn new() -> Self { + Self { + ..Default::default() + } + } } /// 帧缓冲区信息 -pub trait FrameBufferInfo { +pub trait FrameBufferInfo: FrameBufferOps { + fn framebuffer_info_data(&self) -> &RwLock; + /// Amount of ioremapped VRAM or 0 fn screen_size(&self) -> usize; @@ -61,6 +310,54 @@ pub trait FrameBufferInfo { /// 获取帧缓冲区的状态 fn state(&self) -> FbState; + + /// 颜色位深 + fn color_depth(&self) -> u32 { + return 8; + + // 以下逻辑没问题,但是当前没有初始化好var,所以先直接返回当前vasafb的8 + + // let var = self.current_fb_var(); + // let fix = self.current_fb_fix(); + // if fix.visual == FbVisual::Mono01 || fix.visual == FbVisual::Mono10 { + // return 1; + // } else { + // if var.green.length == var.blue.length + // && var.green.length == var.red.length + // && var.green.offset == var.blue.offset + // && var.green.offset == var.red.offset + // { + // kerror!("return {}", var.green.length); + // return var.green.length; + // } else { + // return var.green.length + var.blue.length + var.red.length; + // } + // } + } + + /// ## 设置调色板 + fn set_color_map(&self, cmap: Vec) -> Result<(), SystemError> { + let ret = self.fb_set_color_map(cmap.clone()); + if ret.is_err() && ret.clone().unwrap_err() == SystemError::ENOSYS { + for (idx, color) in cmap.iter().enumerate() { + if self + .fb_set_color_register(idx as u16, color.red, color.green, color.blue) + .is_err() + { + break; + } + } + + self.framebuffer_info_data().write().color_map = cmap; + } else { + if ret.is_ok() { + self.framebuffer_info_data().write().color_map = cmap; + } + return ret; + } + + Ok(()) + } } /// 帧缓冲区操作 @@ -122,6 +419,45 @@ pub trait FrameBufferOps { /// 卸载与该帧缓冲区相关的所有资源 fn fb_destroy(&self); + + /// 画光标 + fn fb_cursor(&self, _cursor: &FbCursor) -> Result<(), SystemError> { + return Err(SystemError::ENOSYS); + } + + /// 画软光标(暂时简要实现) + fn soft_cursor(&self, cursor: FbCursor) -> Result<(), SystemError> { + let mut image = cursor.image.clone(); + if cursor.enable { + match cursor.rop { + true => { + for i in 0..image.data.len() { + image.data[i] ^= cursor.mask[i]; + } + } + false => { + for i in 0..image.data.len() { + image.data[i] &= cursor.mask[i]; + } + } + } + } + + let _ = self.fb_image_blit(&image); + + Ok(()) + } + + fn fb_sync(&self) -> Result<(), SystemError> { + return Err(SystemError::ENOSYS); + } + + /// 绘画位图 + fn fb_image_blit(&self, image: &FbImage); + + fn fb_set_color_map(&self, _cmap: Vec) -> Result<(), SystemError> { + return Err(SystemError::ENOSYS); + } } /// 帧缓冲区的状态 @@ -197,25 +533,27 @@ pub enum FillRectROP { } /// `CopyAreaData` 结构体用于表示一个矩形区域,并指定从哪个源位置复制数据。 +/// +/// 注意,源位置必须是有意义的(即包围的矩形都必须得在屏幕内) #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct CopyAreaData { /// 目标矩形左上角的x坐标 - pub dx: u32, + pub dx: i32, /// 目标矩形左上角的y坐标 - pub dy: u32, + pub dy: i32, /// 矩形的宽度 pub width: u32, /// 矩形的高度 pub height: u32, /// 源矩形左上角的x坐标 - pub sx: u32, + pub sx: i32, /// 源矩形左上角的y坐标 - pub sy: u32, + pub sy: i32, } impl CopyAreaData { #[allow(dead_code)] - pub fn new(dx: u32, dy: u32, width: u32, height: u32, sx: u32, sy: u32) -> Self { + pub fn new(dx: i32, dy: i32, width: u32, height: u32, sx: i32, sy: i32) -> Self { Self { dx, dy, @@ -850,3 +1188,72 @@ pub enum BootTimeVideoType { /// EFI graphic mode Efi, } + +#[derive(Debug, Default)] +pub struct FbCursor { + /// 设置选项 + pub set_mode: FbCursorSetMode, + /// 开关选项 + pub enable: bool, + /// 表示光标图像的位操作,true表示XOR,false表示COPY + pub rop: bool, + /// 表示光标掩码(mask)的数据。掩码用于定义光标的形状,指定了哪些像素是光标的一部分。 + pub mask: Vec, + + /// 表示光标的热点位置,即在光标图像中被认为是"焦点"的位置 + pub hot_x: u32, + pub hot_y: u32, + + /// 光标图像 + pub image: FbImage, +} + +bitflags! { + /// 硬件光标控制 + #[derive(Default)] + pub struct FbCursorSetMode:u8 { + /// 设置位图 + const FB_CUR_SETIMAGE = 0x01; + /// 设置位置 + const FB_CUR_SETPOS = 0x02; + /// 设置热点 + const FB_CUR_SETHOT = 0x04; + /// ColorMap + const FB_CUR_SETCMAP = 0x08; + /// 形状 + const FB_CUR_SETSHAPE = 0x10; + /// Size + const FB_CUR_SETSIZE = 0x20; + /// 全设置 + const FB_CUR_SETALL = 0xFF; + } +} + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy)] +pub enum ScrollMode { + Move, + PanMove, + WrapMove, + Redraw, + PanRedraw, +} + +impl Default for ScrollMode { + /// ## 默认Move + fn default() -> Self { + Self::Move + } +} + +#[derive(Debug, Default, Clone)] +pub struct FbImage { + pub x: u32, + pub y: u32, + pub width: u32, + pub height: u32, + pub fg: u32, + pub bg: u32, + pub depth: u8, + pub data: Vec, +} diff --git a/kernel/src/driver/video/fbdev/vesafb.rs b/kernel/src/driver/video/fbdev/vesafb.rs index a673e9bd..13d312fc 100644 --- a/kernel/src/driver/video/fbdev/vesafb.rs +++ b/kernel/src/driver/video/fbdev/vesafb.rs @@ -28,8 +28,8 @@ use crate::{ CompatibleTable, }, }, - tty::serial::serial8250::send_to_default_serial8250_port, - video::fbdev::base::{fbmem::frame_buffer_manager, FbVisual}, + serial::serial8250::send_to_default_serial8250_port, + video::fbdev::base::{fbmem::frame_buffer_manager, FbVisual, FRAME_BUFFER_SET}, }, filesystem::{ kernfs::KernFSInode, @@ -56,7 +56,7 @@ use crate::{ use super::base::{ fbmem::FbDevice, BlankMode, BootTimeVideoType, FbAccel, FbActivateFlags, FbId, FbState, FbType, FbVModeFlags, FbVarScreenInfo, FbVideoMode, FixedScreenInfo, FrameBuffer, FrameBufferInfo, - FrameBufferOps, + FrameBufferInfoData, FrameBufferOps, }; /// 当前机器上面是否有vesa帧缓冲区 @@ -89,11 +89,14 @@ lazy_static! { pub struct VesaFb { inner: SpinLock, kobj_state: LockedKObjectState, + fb_data: RwLock, } impl VesaFb { pub const NAME: &'static str = "vesa_vga"; pub fn new() -> Self { + let mut fb_info_data = FrameBufferInfoData::new(); + fb_info_data.pesudo_palette.resize(256, 0); return Self { inner: SpinLock::new(InnerVesaFb { bus: None, @@ -111,6 +114,7 @@ impl VesaFb { fb_state: FbState::Suspended, }), kobj_state: LockedKObjectState::new(None), + fb_data: RwLock::new(fb_info_data), }; } } @@ -281,12 +285,46 @@ impl FrameBufferOps for VesaFb { fn fb_set_color_register( &self, - _regno: u16, - _red: u16, - _green: u16, - _blue: u16, + regno: u16, + mut red: u16, + mut green: u16, + mut blue: u16, ) -> Result<(), SystemError> { - todo!() + let mut fb_data = self.framebuffer_info_data().write(); + let var = self.current_fb_var(); + if regno as usize >= fb_data.pesudo_palette.len() { + return Err(SystemError::E2BIG); + } + + if var.bits_per_pixel == 8 { + todo!("vesa_setpalette todo"); + } else if regno < 16 { + match var.bits_per_pixel { + 16 => { + if var.red.offset == 10 { + // RGB 1:5:5:5 + fb_data.pesudo_palette[regno as usize] = ((red as u32 & 0xf800) >> 1) + | ((green as u32 & 0xf800) >> 6) + | ((blue as u32 & 0xf800) >> 11); + } else { + fb_data.pesudo_palette[regno as usize] = (red as u32 & 0xf800) + | ((green as u32 & 0xfc00) >> 5) + | ((blue as u32 & 0xf800) >> 11); + } + } + 24 | 32 => { + red >>= 8; + green >>= 8; + blue >>= 8; + fb_data.pesudo_palette[regno as usize] = ((red as u32) << var.red.offset) + | ((green as u32) << var.green.offset) + | ((blue as u32) << var.blue.offset); + } + _ => {} + } + } + + Ok(()) } fn fb_blank(&self, _blank_mode: BlankMode) -> Result<(), SystemError> { @@ -338,6 +376,138 @@ impl FrameBufferOps for VesaFb { return Ok(len); } + + fn fb_image_blit(&self, image: &super::base::FbImage) { + self.generic_imageblit(image); + } + + /// ## 填充矩形 + fn fb_fillrect(&self, rect: super::base::FillRectData) -> Result<(), SystemError> { + // kwarn!("rect {rect:?}"); + + let boot_param = boot_params().read(); + let screen_base = boot_param + .screen_info + .lfb_virt_base + .ok_or(SystemError::ENODEV)?; + let fg; + if self.current_fb_fix().visual == FbVisual::TrueColor + || self.current_fb_fix().visual == FbVisual::DirectColor + { + fg = self.fb_data.read().pesudo_palette[rect.color as usize]; + } else { + fg = rect.color; + } + + let bpp = self.current_fb_var().bits_per_pixel; + // 每行像素数 + let line_offset = self.current_fb_var().xres; + match bpp { + 32 => { + let base = screen_base.as_ptr::(); + + for y in rect.dy..(rect.dy + rect.height) { + for x in rect.dx..(rect.dx + rect.width) { + unsafe { *base.add((y * line_offset + x) as usize) = fg }; + } + } + } + _ => todo!(), + } + + Ok(()) + } + + fn fb_copyarea(&self, data: super::base::CopyAreaData) -> Result<(), SystemError> { + let bp = boot_params().read(); + let base = bp.screen_info.lfb_virt_base.ok_or(SystemError::ENODEV)?; + let var = self.current_fb_var(); + + if data.sx < 0 + || data.sy < 0 + || data.sx as u32 > var.xres + || data.sx as u32 + data.width > var.xres + || data.sy as u32 > var.yres + || data.sy as u32 + data.height > var.yres + { + return Err(SystemError::EINVAL); + } + + let bytes_per_pixel = var.bits_per_pixel >> 3; + let bytes_per_line = var.xres * bytes_per_pixel; + + let sy = data.sy as u32; + let sx = data.sx as u32; + + let dst = { + let mut dst = base; + if data.dy < 0 { + dst -= VirtAddr::new((((-data.dy) as u32) * bytes_per_line) as usize); + } else { + dst += VirtAddr::new(((data.dy as u32) * bytes_per_line) as usize); + } + + if data.dx > 0 && (data.dx as u32) < var.xres { + dst += VirtAddr::new(((data.dx as u32) * bytes_per_pixel) as usize); + } + + dst + }; + let src = base + VirtAddr::new((sy * bytes_per_line + sx * bytes_per_pixel) as usize); + + match bytes_per_pixel { + 4 => { + // 32bpp + let mut dst = dst.as_ptr::(); + let mut src = src.as_ptr::(); + + for y in 0..data.height as usize { + if (data.dy + y as i32) < 0 || (data.dy + y as i32) > var.yres as i32 { + unsafe { + // core::ptr::copy(src, dst, data.width as usize); + src = src.add(var.xres as usize); + dst = dst.add(var.xres as usize); + } + continue; + } + if data.dx < 0 { + if ((-data.dx) as u32) < data.width { + unsafe { + core::ptr::copy( + src.add((-data.dx) as usize), + dst, + (data.width as usize) - (-data.dx) as usize, + ); + src = src.add(var.xres as usize); + dst = dst.add(var.xres as usize); + } + } + } else if data.dx as u32 + data.width > var.xres { + if (data.dx as u32) < var.xres { + unsafe { + core::ptr::copy(src, dst, (var.xres - data.dx as u32) as usize); + src = src.add(var.xres as usize); + dst = dst.add(var.xres as usize); + } + } + } else { + for i in 0..data.width as usize { + unsafe { *(dst.add(i)) = *(src.add(i)) } + } + unsafe { + // core::ptr::copy(src, dst, data.width as usize); + src = src.add(var.xres as usize); + dst = dst.add(var.xres as usize); + } + } + } + } + _ => { + todo!() + } + } + Ok(()) + } } impl FrameBufferInfo for VesaFb { @@ -368,6 +538,10 @@ impl FrameBufferInfo for VesaFb { fn state(&self) -> FbState { self.inner.lock().fb_state } + + fn framebuffer_info_data(&self) -> &RwLock { + &self.fb_data + } } #[derive(Debug)] @@ -679,36 +853,54 @@ fn vesa_fb_device_init() -> Result<(), SystemError> { static INIT: Once = Once::new(); INIT.call_once(|| { kinfo!("vesa fb device init"); + let device = Arc::new(VesaFb::new()); - let mut fix_info_guard = VESAFB_FIX_INFO.write_irqsave(); - let mut var_info_guard = VESAFB_DEFINED.write_irqsave(); + let mut fb_fix = VESAFB_FIX_INFO.write_irqsave(); + let mut fb_var = VESAFB_DEFINED.write_irqsave(); let boot_params_guard = boot_params().read(); let boottime_screen_info = &boot_params_guard.screen_info; - fix_info_guard.smem_start = Some(boottime_screen_info.lfb_base); - fix_info_guard.smem_len = boottime_screen_info.lfb_size; + fb_fix.smem_start = Some(boottime_screen_info.lfb_base); + fb_fix.smem_len = boottime_screen_info.lfb_size; if boottime_screen_info.video_type == BootTimeVideoType::Mda { - fix_info_guard.visual = FbVisual::Mono10; - var_info_guard.bits_per_pixel = 8; - fix_info_guard.line_length = (boottime_screen_info.origin_video_cols as u32) - * (var_info_guard.bits_per_pixel / 8); - var_info_guard.xres_virtual = boottime_screen_info.origin_video_cols as u32; - var_info_guard.yres_virtual = boottime_screen_info.origin_video_lines as u32; + fb_fix.visual = FbVisual::Mono10; + fb_var.bits_per_pixel = 8; + fb_fix.line_length = + (boottime_screen_info.origin_video_cols as u32) * (fb_var.bits_per_pixel / 8); + fb_var.xres_virtual = boottime_screen_info.origin_video_cols as u32; + fb_var.yres_virtual = boottime_screen_info.origin_video_lines as u32; } else { - fix_info_guard.visual = FbVisual::TrueColor; - var_info_guard.bits_per_pixel = boottime_screen_info.lfb_depth as u32; - fix_info_guard.line_length = - (boottime_screen_info.lfb_width as u32) * (var_info_guard.bits_per_pixel / 8); - var_info_guard.xres_virtual = boottime_screen_info.lfb_width as u32; - var_info_guard.yres_virtual = boottime_screen_info.lfb_height as u32; + fb_fix.visual = FbVisual::TrueColor; + fb_var.bits_per_pixel = boottime_screen_info.lfb_depth as u32; + fb_fix.line_length = + (boottime_screen_info.lfb_width as u32) * (fb_var.bits_per_pixel / 8); + fb_var.xres_virtual = boottime_screen_info.lfb_width as u32; + fb_var.yres_virtual = boottime_screen_info.lfb_height as u32; + fb_var.xres = boottime_screen_info.lfb_width as u32; + fb_var.yres = boottime_screen_info.lfb_height as u32; } - drop(var_info_guard); - drop(fix_info_guard); + fb_var.red.length = boottime_screen_info.red_size as u32; + fb_var.green.length = boottime_screen_info.green_size as u32; + fb_var.blue.length = boottime_screen_info.blue_size as u32; + + fb_var.red.offset = boottime_screen_info.red_pos as u32; + fb_var.green.offset = boottime_screen_info.green_pos as u32; + fb_var.blue.offset = boottime_screen_info.blue_pos as u32; + + // TODO: 这里是暂时这样写的,初始化为RGB888格式,后续vesa初始化完善后删掉下面 + fb_var.red.offset = 16; + fb_var.green.offset = 8; + fb_var.blue.offset = 0; + + if fb_var.bits_per_pixel >= 1 && fb_var.bits_per_pixel <= 8 { + fb_var.red.length = fb_var.bits_per_pixel; + fb_var.green.length = fb_var.bits_per_pixel; + fb_var.blue.length = fb_var.bits_per_pixel; + } - let device = Arc::new(VesaFb::new()); device_manager().device_default_initialize(&(device.clone() as Arc)); platform_device_manager() @@ -719,6 +911,16 @@ fn vesa_fb_device_init() -> Result<(), SystemError> { .register_fb(device.clone() as Arc) .expect("vesa_fb_device_init: frame_buffer_manager().register_fb failed"); + // 加入全局fb表 + let mut guard = FRAME_BUFFER_SET.write(); + if guard.get(device.fb_id().data() as usize).unwrap().is_some() { + kwarn!( + "vesa_fb_device_init: There is already an element {:?} in the FRAME_BUFFER_SET", + device.fb_id() + ); + } + guard[device.fb_id().data() as usize] = Some(device.clone()); + // 设置vesa fb的状态为运行中 device.inner.lock().fb_state = FbState::Running; }); diff --git a/kernel/src/driver/video/mod.rs b/kernel/src/driver/video/mod.rs index 80f92992..569029fb 100644 --- a/kernel/src/driver/video/mod.rs +++ b/kernel/src/driver/video/mod.rs @@ -2,7 +2,6 @@ use core::sync::atomic::{AtomicBool, Ordering}; use crate::{ arch::MMArch, - driver::tty::serial::serial8250::send_to_default_serial8250_port, init::boot_params, kinfo, libs::{ @@ -176,7 +175,10 @@ impl VideoRefreshManager { pub unsafe fn video_init() -> Result<(), SystemError> { use crate::{ arch::driver::video::arch_video_early_init, - driver::video::fbdev::base::BootTimeVideoType, + driver::{ + serial::serial8250::send_to_default_serial8250_port, + video::fbdev::base::BootTimeVideoType, + }, }; arch_video_early_init()?; diff --git a/kernel/src/filesystem/devfs/mod.rs b/kernel/src/filesystem/devfs/mod.rs index 1e2cdaf9..e77b0243 100644 --- a/kernel/src/filesystem/devfs/mod.rs +++ b/kernel/src/filesystem/devfs/mod.rs @@ -6,7 +6,7 @@ use super::vfs::{ core::{generate_inode_id, ROOT_INODE}, file::FileMode, syscall::ModeType, - FileSystem, FileType, FsInfo, IndexNode, Metadata, + FilePrivateData, FileSystem, FileType, FsInfo, IndexNode, Metadata, }; use crate::{ driver::base::device::device_number::DeviceNumber, @@ -461,7 +461,12 @@ impl IndexNode for LockedDevFSInode { } } - fn ioctl(&self, _cmd: u32, _data: usize) -> Result { + fn ioctl( + &self, + _cmd: u32, + _data: usize, + _private_data: &FilePrivateData, + ) -> Result { Err(SystemError::EOPNOTSUPP_OR_ENOTSUP) } diff --git a/kernel/src/filesystem/kernfs/mod.rs b/kernel/src/filesystem/kernfs/mod.rs index 268d6da7..2bebbbaa 100644 --- a/kernel/src/filesystem/kernfs/mod.rs +++ b/kernel/src/filesystem/kernfs/mod.rs @@ -258,7 +258,12 @@ impl IndexNode for KernFSInode { return Ok((name, entry.metadata()?)); } - fn ioctl(&self, _cmd: u32, _data: usize) -> Result { + fn ioctl( + &self, + _cmd: u32, + _data: usize, + _private_data: &FilePrivateData, + ) -> Result { // 若文件系统没有实现此方法,则返回“不支持” return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); } diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index 05e9cd40..791962db 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -8,7 +8,7 @@ use system_error::SystemError; use crate::{ driver::{ base::{block::SeekFrom, device::DevicePrivateData}, - tty::TtyFilePrivateData, + tty::tty_device::TtyFilePrivateData, }, filesystem::procfs::ProcfsFilePrivateData, ipc::pipe::{LockedPipeInode, PipeFsPrivateData}, diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index 22c2dcd7..0354e0ff 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -339,7 +339,12 @@ pub trait IndexNode: Any + Sync + Send + Debug { /// /// @return 成功:Ok() /// 失败:Err(错误码) - fn ioctl(&self, _cmd: u32, _data: usize) -> Result { + fn ioctl( + &self, + _cmd: u32, + _data: usize, + _private_data: &FilePrivateData, + ) -> Result { // 若文件系统没有实现此方法,则返回“不支持” return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); } diff --git a/kernel/src/filesystem/vfs/mount.rs b/kernel/src/filesystem/vfs/mount.rs index 31bca7a8..908800ab 100644 --- a/kernel/src/filesystem/vfs/mount.rs +++ b/kernel/src/filesystem/vfs/mount.rs @@ -317,8 +317,13 @@ impl IndexNode for MountFSInode { } #[inline] - fn ioctl(&self, cmd: u32, data: usize) -> Result { - return self.inner_inode.ioctl(cmd, data); + fn ioctl( + &self, + cmd: u32, + data: usize, + private_data: &FilePrivateData, + ) -> Result { + return self.inner_inode.ioctl(cmd, data, private_data); } #[inline] diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall.rs index 3e8beae0..e2ff1192 100644 --- a/kernel/src/filesystem/vfs/syscall.rs +++ b/kernel/src/filesystem/vfs/syscall.rs @@ -297,7 +297,8 @@ impl Syscall { // drop guard 以避免无法调度的问题 drop(fd_table_guard); - let r = file.lock_no_preempt().inode().ioctl(cmd, data); + let file = file.lock_no_preempt(); + let r = file.inode().ioctl(cmd, data, &file.private_data); return r; } @@ -683,7 +684,7 @@ impl Syscall { for i in arg..FileDescriptorVec::PROCESS_MAX_FD { let binding = ProcessManager::current_pcb().fd_table(); let mut fd_table_guard = binding.write(); - if fd_table_guard.get_file_by_fd(fd).is_none() { + if fd_table_guard.get_file_by_fd(i as i32).is_none() { return Self::do_dup2(fd, i as i32, &mut fd_table_guard); } } diff --git a/kernel/src/init/init.rs b/kernel/src/init/init.rs index 641793a5..7d405b53 100644 --- a/kernel/src/init/init.rs +++ b/kernel/src/init/init.rs @@ -3,7 +3,7 @@ use crate::{ init::{early_setup_arch, setup_arch, setup_arch_post}, CurrentIrqArch, CurrentSMPArch, CurrentSchedArch, }, - driver::{base::init::driver_init, tty::init::tty_early_init, video::VideoRefreshManager}, + driver::{base::init::driver_init, serial::serial_early_init, video::VideoRefreshManager}, exception::{init::irq_init, softirq::softirq_init, InterruptArch}, filesystem::vfs::core::vfs_init, include::bindings::bindings::acpi_init, @@ -81,7 +81,7 @@ fn do_start_kernel() { /// 在内存管理初始化之前,执行的初始化 #[inline(never)] fn init_before_mem_init() { - tty_early_init().expect("tty early init failed"); + serial_early_init().expect("serial early init failed"); let video_ok = unsafe { VideoRefreshManager::video_init().is_ok() }; scm_init(video_ok); } diff --git a/kernel/src/libs/font/bin/VGA_8X16.bytes b/kernel/src/libs/font/bin/VGA_8X16.bytes new file mode 100644 index 0000000000000000000000000000000000000000..0f3cbdf6e199ce54e28ba49dafd83ba0ba5c54d9 GIT binary patch literal 4096 zcmZu!y=xpt6dxSeYB?+25(~L;;c{`{yo5yplYb#isznYP7ei2WImoiM8vhSYpCyKmn2$Gn*{W*^$~zs}F!zdJu~h0^Y> zcDu{XZl}00wgWW9ftNfeni$Q>a(G`X%7k&CN^}vh1qdlvm3C zW_EqM?Y6hqvo}nBkc^IwyW^u#@<7>3sLopNupx5*Jca)H>gwu`M+A&Ft}3i^wn$wg z4E#+g6BOwXeVR|fv84Xf8=yCcbfsOYRMwGKU6n`5&1^PP?Y#QbcJ^scKPZZ(@#e9N z;x$EIzMhfaP@59=jrxO7pA0!HwDUhLXIbMeW=)d3b&ZeU!lhYWxwj%#SX)e1sMmyX zl%^7beuI}GOJyO?QiiOLur7C{W}A7C9d9eBg3G;tiL;?By~Klr{L^|Hs@7sb6%)p+ zm_ipo>(e-4cd8S3QYJ~_%bOmScHY6|Ba!b=jQfaQRKOiT+o6NJ#4P*`ks><1w~$Y# z>bO**ci-baTy_sxOFX}U=juEyRYaqRg%15GqVx4N1`F%;dNou34k#fVIVAk|=zxYg z{$B91zCeVt3*De*Yl&Fbb}RI*K7BQPRh`zFFU70sHj-aESN|Y5Sz>c)kD8C66#5Z& zL%-i|U}`#r(Ho)PRt&+O`_y$PCqVVz+;!^@Jo9M@8u45qc9^!29R7^lDP~{lW6+055-#=l2xe_z)BU4ll|FSqt+8 zEYbj4f5L51#C2kR41v^dsX5J4-A^NgdPWK2?xYFqL5vfPc(OCbCo5TwzIlgxb*A6X zA~826_8+}Bs3(NYpg+JLEws@58ESsgMLBTVx08FxT(#cKQf#Q1%<2i zC;k|BhQp-^L#E*l;bFevT$KS8<_DNQj>qkC`5W;Yb8P4HjxzFrQSp~5r2WJG_PF@l zM3Z;uXK-hFx?6!w>jN8rsp`-gi8U54n6!T5GQ z-~KaS!z9OVMvp)t>QefH&V{%>RPQ){L>G_5AHoOzqrsy61>QK-3N^3 zjyUohf7Q&#$3k?5&iGBfI@Uqe6Jg<_jW01l!PqYCIAF#A zvrECh{c-sD>F?p^-`|HHB<^dl9V~9MfR6?4^y$6m2KYYzT@v^`pMSE~-5&ie(b-^( z@&%mzg8nFadJX=m-;X_Aak+>4MPqil?jMi+i?RfMFYoF6e4GV-_3yclho8^$lin2G zPVyoBvkCf{Z)ZO5$p?O=2Y%-J-1DC=3g_z{{#rZm8k;zK3%ZO<)!2uXrg8S>IzmF5{$lNEP zAK}Jw%o2j*yTwm1l?L`r0{p*LjhVx|s$jax50&4~SLfxiS>#U_^yh`wsMqH(!!RKc zaq98WBbumRK%9UKyfTf&0){011b7_kd;iek9Ts}&hkU*JXl*I+SnjOAh~qrXo_W`0 LxfSSnqPPD6Uqait literal 0 HcmV?d00001 diff --git a/kernel/src/libs/font/bin/VGA_8X8.bytes b/kernel/src/libs/font/bin/VGA_8X8.bytes new file mode 100644 index 0000000000000000000000000000000000000000..824b61dede6a4f6f2907386bdd0cc01f64d4d065 GIT binary patch literal 2048 zcmX|Cy=o*!5H1vqlVPQ>VTAN(H^Kiha<&L|EpN0+jzf{On5Db`}_N5#yEoaUbfcO)^2f}s2k36Q{fz{jf9hTvv(&U z@$xZ#zqMZo_QZXt9>~Z6%79~+wXJ5AUCU!xmM6%^e?;wUZ^02SsE+$(B3ZZ+P8`=#1ga2KugJ7*>wL2+tEol2N{Sd~ zCRvstmQ~3DtfQ83iF^q2`5b%+d^QL(W;;W!2^jGXAWsv%YwBz(T5q);?ZXaX#5k}G z`J*9Y{@^SCWp=<8hy0~_?PQ?TsZs;9K_sC7l}wi~C9x2mebyk&eAf2(xk`D~m#H3J z64$EdI&t`E8kZOKWwPgqvOc=sZ~J=Gmjwba&{JW=!z~&H{RVq*r9-oc7t|?t=VXj_ zZ`)fTF6)yzCE-$@{lY+}=;KrmbX3fnxU5T*VTbF7_>?NDZy!taGmZofl-jiIfBtX( zelS!<-JQaJ$_Fze#>f2WNA>uq7Y~eeW9N#gsxj|TQNbCGkCR7F#;ho=D4B#T6Pc_l zcVydL@E=Ft|C`Y+4ooQR5v=fQTanLyOV3w-rss!$(u1OXqD@?F6!{4Bgf}{h{6+ti zQU5{=<0%SHS%5K@EyZpPCZbgel&WHdU~TBO`C{yXg$)l0lDc`@#; zC)#uQ*wb!L)bShc-SV&HRAy~^*ZLOo19LAPB&I*+fAFO)aZk|icX#L)40ur8U>i#! zP8m)f7uy;w5!{qN6?D2`H`d literal 0 HcmV?d00001 diff --git a/kernel/src/libs/font/font_type/mod.rs b/kernel/src/libs/font/font_type/mod.rs new file mode 100644 index 00000000..1ddc6823 --- /dev/null +++ b/kernel/src/libs/font/font_type/mod.rs @@ -0,0 +1,2 @@ +pub mod vga8x16; +pub mod vga8x8; diff --git a/kernel/src/libs/font/font_type/vga8x16.rs b/kernel/src/libs/font/font_type/vga8x16.rs new file mode 100644 index 00000000..49985ffd --- /dev/null +++ b/kernel/src/libs/font/font_type/vga8x16.rs @@ -0,0 +1,10 @@ +use crate::libs::font::FontDesc; + +pub const FONT_VGA_8X16: FontDesc = FontDesc { + index: 1, + name: "VGA8x16", + width: 8, + height: 16, + char_count: 256, + data: include_bytes!("../bin/VGA_8X16.bytes"), +}; diff --git a/kernel/src/libs/font/font_type/vga8x8.rs b/kernel/src/libs/font/font_type/vga8x8.rs new file mode 100644 index 00000000..bf70228a --- /dev/null +++ b/kernel/src/libs/font/font_type/vga8x8.rs @@ -0,0 +1,11 @@ +use crate::libs::font::FontDesc; + +#[allow(dead_code)] +pub const FONT_VGA_8X8: FontDesc = FontDesc { + index: 0, + name: "VGA8x8", + width: 8, + height: 8, + char_count: 256, + data: include_bytes!("../bin/VGA_8X8.bytes"), +}; diff --git a/kernel/src/libs/font/mod.rs b/kernel/src/libs/font/mod.rs new file mode 100644 index 00000000..02309e63 --- /dev/null +++ b/kernel/src/libs/font/mod.rs @@ -0,0 +1,49 @@ +use self::font_type::vga8x16::FONT_VGA_8X16; + +pub mod font_type; + +pub struct FontDesc { + pub index: usize, + pub name: &'static str, + pub width: u32, + pub height: u32, + pub char_count: u32, + pub data: &'static [u8], +} + +impl FontDesc { + pub fn get_default_font(_xres: u32, _yres: u32, _font_w: u32, _font_h: u32) -> &'static Self { + // todo: 目前先直接返回一个字体 + &FONT_VGA_8X16 + } + + pub const DOUBLE_WIDTH_RANGE: &'static [(u32, u32)] = &[ + (0x1100, 0x115F), + (0x2329, 0x232A), + (0x2E80, 0x303E), + (0x3040, 0xA4CF), + (0xAC00, 0xD7A3), + (0xF900, 0xFAFF), + (0xFE10, 0xFE19), + (0xFE30, 0xFE6F), + (0xFF00, 0xFF60), + (0xFFE0, 0xFFE6), + (0x20000, 0x2FFFD), + (0x30000, 0x3FFFD), + ]; + pub fn is_double_width(ch: u32) -> bool { + if ch < Self::DOUBLE_WIDTH_RANGE.first().unwrap().0 + || ch > Self::DOUBLE_WIDTH_RANGE.last().unwrap().1 + { + return false; + } + + for (first, last) in Self::DOUBLE_WIDTH_RANGE { + if ch > *first && ch < *last { + return true; + } + } + + false + } +} diff --git a/kernel/src/libs/keyboard_parser.rs b/kernel/src/libs/keyboard_parser.rs index 35cb455d..00ecf974 100644 --- a/kernel/src/libs/keyboard_parser.rs +++ b/kernel/src/libs/keyboard_parser.rs @@ -1,6 +1,11 @@ +use core::sync::atomic::Ordering; + use alloc::sync::Arc; -use crate::driver::tty::tty_device::TtyDevice; +use crate::driver::tty::{ + tty_port::{TtyPort, TTY_PORTS}, + virtual_terminal::virtual_console::CURRENT_VCNUM, +}; #[allow(dead_code)] pub const NUM_SCAN_CODES: u8 = 0x80; @@ -28,25 +33,21 @@ pub enum KeyFlag { pub struct TypeOneFSM { status: ScanCodeStatus, current_state: TypeOneFSMState, - tty: Arc, } impl TypeOneFSM { #[allow(dead_code)] - pub fn new(tty: Arc) -> Self { + pub fn new() -> Self { Self { status: ScanCodeStatus::new(), current_state: TypeOneFSMState::Start, - tty, } } /// @brief 解析扫描码 #[allow(dead_code)] pub fn parse(&mut self, scancode: u8) -> TypeOneFSMState { - self.current_state = self - .current_state - .parse(scancode, &mut self.status, &self.tty); + self.current_state = self.current_state.parse(scancode, &mut self.status); self.current_state } } @@ -69,42 +70,30 @@ pub enum TypeOneFSMState { impl TypeOneFSMState { /// @brief 状态机总控程序 - fn parse( - &self, - scancode: u8, - scancode_status: &mut ScanCodeStatus, - tty: &Arc, - ) -> TypeOneFSMState { + fn parse(&self, scancode: u8, scancode_status: &mut ScanCodeStatus) -> TypeOneFSMState { // kdebug!("the code is {:#x}\n", scancode); match self { TypeOneFSMState::Start => { - return self.handle_start(scancode, scancode_status, tty); + return self.handle_start(scancode, scancode_status); } TypeOneFSMState::PauseBreak(n) => { - return self.handle_pause_break(*n, scancode_status, tty); + return self.handle_pause_break(*n, scancode_status); } TypeOneFSMState::Func0 => { - return self.handle_func0(scancode, scancode_status, tty); + return self.handle_func0(scancode, scancode_status); } TypeOneFSMState::Type3 => { - return self.handle_type3(scancode, scancode_status, tty); - } - TypeOneFSMState::PrtscPress(n) => { - return self.handle_prtsc_press(*n, scancode_status, tty) + return self.handle_type3(scancode, scancode_status); } + TypeOneFSMState::PrtscPress(n) => return self.handle_prtsc_press(*n, scancode_status), TypeOneFSMState::PrtscRelease(n) => { - return self.handle_prtsc_release(*n, scancode_status, tty) + return self.handle_prtsc_release(*n, scancode_status) } } } /// @brief 处理起始状态 - fn handle_start( - &self, - scancode: u8, - scancode_status: &mut ScanCodeStatus, - tty: &Arc, - ) -> TypeOneFSMState { + fn handle_start(&self, scancode: u8, scancode_status: &mut ScanCodeStatus) -> TypeOneFSMState { //kdebug!("in handle_start the code is {:#x}\n",scancode); match scancode { 0xe1 => { @@ -115,7 +104,7 @@ impl TypeOneFSMState { } _ => { //kdebug!("in _d the code is {:#x}\n",scancode); - return TypeOneFSMState::Type3.handle_type3(scancode, scancode_status, tty); + return TypeOneFSMState::Type3.handle_type3(scancode, scancode_status); } } } @@ -125,17 +114,16 @@ impl TypeOneFSMState { &self, scancode: u8, scancode_status: &mut ScanCodeStatus, - tty: &Arc, ) -> TypeOneFSMState { static PAUSE_BREAK_SCAN_CODE: [u8; 6] = [0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5]; let i = match self { TypeOneFSMState::PauseBreak(i) => *i, _ => { - return self.handle_type3(scancode, scancode_status, tty); + return self.handle_type3(scancode, scancode_status); } }; if scancode != PAUSE_BREAK_SCAN_CODE[i as usize] { - return self.handle_type3(scancode, scancode_status, tty); + return self.handle_type3(scancode, scancode_status); } else { if i == 5 { // 所有Pause Break扫描码都被清除 @@ -146,12 +134,7 @@ impl TypeOneFSMState { } } - fn handle_func0( - &self, - scancode: u8, - scancode_status: &mut ScanCodeStatus, - tty: &Arc, - ) -> TypeOneFSMState { + fn handle_func0(&self, scancode: u8, scancode_status: &mut ScanCodeStatus) -> TypeOneFSMState { //0xE0 match scancode { 0x2a => { @@ -214,7 +197,7 @@ impl TypeOneFSMState { } 0x53 => { scancode_status.del = true; - Self::emit(tty, 127); + Self::emit(127); } 0xd3 => { scancode_status.del = false; @@ -233,32 +216,32 @@ impl TypeOneFSMState { } 0x48 => { scancode_status.arrow_u = true; - Self::emit(tty, 224); - Self::emit(tty, 72); + Self::emit(224); + Self::emit(72); } 0xc8 => { scancode_status.arrow_u = false; } 0x4b => { scancode_status.arrow_l = true; - Self::emit(tty, 224); - Self::emit(tty, 75); + Self::emit(224); + Self::emit(75); } 0xcb => { scancode_status.arrow_l = false; } 0x50 => { scancode_status.arrow_d = true; - Self::emit(tty, 224); - Self::emit(tty, 80); + Self::emit(224); + Self::emit(80); } 0xd0 => { scancode_status.arrow_d = false; } 0x4d => { scancode_status.arrow_r = true; - Self::emit(tty, 224); - Self::emit(tty, 77); + Self::emit(224); + Self::emit(77); } 0xcd => { scancode_status.arrow_r = false; @@ -269,14 +252,14 @@ impl TypeOneFSMState { scancode_status.kp_forward_slash = true; let ch = '/' as u8; - Self::emit(tty, ch); + Self::emit(ch); } 0xb5 => { scancode_status.kp_forward_slash = false; } 0x1c => { scancode_status.kp_enter = true; - Self::emit(tty, '\n' as u8); + Self::emit('\n' as u8); } 0x9c => { scancode_status.kp_enter = false; @@ -288,12 +271,7 @@ impl TypeOneFSMState { return TypeOneFSMState::Start; } - fn handle_type3( - &self, - scancode: u8, - scancode_status: &mut ScanCodeStatus, - tty: &Arc, - ) -> TypeOneFSMState { + fn handle_type3(&self, scancode: u8, scancode_status: &mut ScanCodeStatus) -> TypeOneFSMState { // 判断按键是被按下还是抬起 let flag_make = if (scancode & (TYPE1_KEYCODE_FLAG_BREAK as u8)) > 0 { false //up @@ -358,18 +336,36 @@ impl TypeOneFSMState { } } - let ch = TYPE1_KEY_CODE_MAPTABLE[col as usize + 2 * index as usize]; + let mut ch = TYPE1_KEY_CODE_MAPTABLE[col as usize + 2 * index as usize]; if key != KeyFlag::NoneFlag { // kdebug!("EMIT: ch is '{}', keyflag is {:?}\n", ch as char, key); - Self::emit(tty, ch); + if scancode_status.ctrl_l || scancode_status.ctrl_r { + ch = Self::to_ctrl(ch); + } + Self::emit(ch); } return TypeOneFSMState::Start; } + #[inline] + fn to_ctrl(ch: u8) -> u8 { + return match ch as char { + 'a'..='z' => ch - 0x40, + 'A'..='Z' => ch - 0x40, + '@'..='_' => ch - 0x40, + _ => ch, + }; + } + #[inline(always)] - fn emit(tty: &Arc, ch: u8) { + fn emit(ch: u8) { // 发送到tty - tty.input(&[ch]).ok(); + let _ = Self::current_port().receive_buf(&[ch], &[], 1); + } + + #[inline] + fn current_port() -> Arc { + TTY_PORTS[CURRENT_VCNUM.load(Ordering::SeqCst) as usize].clone() } /// @brief 处理Prtsc按下事件 @@ -377,7 +373,6 @@ impl TypeOneFSMState { &self, scancode: u8, scancode_status: &mut ScanCodeStatus, - tty: &Arc, ) -> TypeOneFSMState { static PRTSC_SCAN_CODE: [u8; 4] = [0xe0, 0x2a, 0xe0, 0x37]; let i = match self { @@ -389,7 +384,7 @@ impl TypeOneFSMState { return TypeOneFSMState::Start; } if scancode != PRTSC_SCAN_CODE[i as usize] { - return self.handle_type3(scancode, scancode_status, tty); + return self.handle_type3(scancode, scancode_status); } else { if i == 3 { // 成功解析出PrtscPress @@ -405,7 +400,6 @@ impl TypeOneFSMState { &self, scancode: u8, scancode_status: &mut ScanCodeStatus, - tty: &Arc, ) -> TypeOneFSMState { static PRTSC_SCAN_CODE: [u8; 4] = [0xe0, 0xb7, 0xe0, 0xaa]; let i = match self { @@ -417,7 +411,7 @@ impl TypeOneFSMState { return TypeOneFSMState::Start; } if scancode != PRTSC_SCAN_CODE[i as usize] { - return self.handle_type3(scancode, scancode_status, tty); + return self.handle_type3(scancode, scancode_status); } else { if i == 3 { // 成功解析出PrtscRelease diff --git a/kernel/src/libs/lib_ui/screen_manager.rs b/kernel/src/libs/lib_ui/screen_manager.rs index dfcc1521..47d66351 100644 --- a/kernel/src/libs/lib_ui/screen_manager.rs +++ b/kernel/src/libs/lib_ui/screen_manager.rs @@ -8,9 +8,7 @@ use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc}; use system_error::SystemError; use crate::{ - driver::{ - tty::serial::serial8250::send_to_default_serial8250_port, video::video_refresh_manager, - }, + driver::{serial::serial8250::send_to_default_serial8250_port, video::video_refresh_manager}, libs::{lib_ui::textui::textui_is_enable_put_to_window, rwlock::RwLock, spinlock::SpinLock}, mm::VirtAddr, }; diff --git a/kernel/src/libs/lib_ui/textui.rs b/kernel/src/libs/lib_ui/textui.rs index 03bbfb1a..90f6e857 100644 --- a/kernel/src/libs/lib_ui/textui.rs +++ b/kernel/src/libs/lib_ui/textui.rs @@ -1,6 +1,11 @@ use crate::{ driver::{ - tty::serial::serial8250::send_to_default_serial8250_port, video::video_refresh_manager, + serial::serial8250::send_to_default_serial8250_port, + tty::{ + tty_driver::TtyOperation, tty_port::TTY_PORTS, + virtual_terminal::virtual_console::CURRENT_VCNUM, + }, + video::video_refresh_manager, }, kdebug, kinfo, libs::{ @@ -984,6 +989,29 @@ where #[no_mangle] pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 { + let current_vcnum = CURRENT_VCNUM.load(Ordering::SeqCst); + if current_vcnum != -1 { + // tty已经初始化了之后才输出到屏幕 + let fr = (fr_color & 0x00ff0000) >> 16; + let fg = (fr_color & 0x0000ff00) >> 8; + let fb = fr_color & 0x000000ff; + let br = (bk_color & 0x00ff0000) >> 16; + let bg = (bk_color & 0x0000ff00) >> 8; + let bb = bk_color & 0x000000ff; + let buf = format!( + "\x1B[38;2;{fr};{fg};{fb};48;2;{br};{bg};{bb}m{}\x1B[0m", + character as char + ); + let port = TTY_PORTS[current_vcnum as usize].clone(); + let tty = port.port_data().tty(); + if tty.is_some() { + let tty = tty.unwrap(); + return tty + .write(tty.core(), buf.as_bytes(), buf.len()) + .map(|_| 0) + .unwrap_or_else(|e| e.to_posix_errno()); + } + } return textui_putchar( character as char, FontColor::from(fr_color), diff --git a/kernel/src/libs/lib_ui/textui_no_alloc.rs b/kernel/src/libs/lib_ui/textui_no_alloc.rs index 10fee12d..208690ce 100644 --- a/kernel/src/libs/lib_ui/textui_no_alloc.rs +++ b/kernel/src/libs/lib_ui/textui_no_alloc.rs @@ -6,7 +6,7 @@ use core::{ use system_error::SystemError; use crate::driver::{ - tty::serial::serial8250::send_to_default_serial8250_port, video::video_refresh_manager, + serial::serial8250::send_to_default_serial8250_port, video::video_refresh_manager, }; use super::textui::{ diff --git a/kernel/src/libs/mod.rs b/kernel/src/libs/mod.rs index 7a23aa53..f15630bd 100644 --- a/kernel/src/libs/mod.rs +++ b/kernel/src/libs/mod.rs @@ -25,3 +25,5 @@ pub mod volatile; pub mod futex; pub mod rand; pub mod wait_queue; + +pub mod font; diff --git a/kernel/src/libs/printk.rs b/kernel/src/libs/printk.rs index 071fd5ef..e364f6ba 100644 --- a/kernel/src/libs/printk.rs +++ b/kernel/src/libs/printk.rs @@ -1,10 +1,20 @@ -use core::fmt::{self, Write}; +use core::{ + fmt::{self, Write}, + sync::atomic::Ordering, +}; use alloc::string::ToString; use super::lib_ui::textui::{textui_putstr, FontColor}; use crate::{ + driver::{ + serial::serial8250::send_to_default_serial8250_port, + tty::{ + tty_driver::TtyOperation, tty_port::TTY_PORTS, + virtual_terminal::virtual_console::CURRENT_VCNUM, + }, + }, filesystem::procfs::{ kmsg::KMSG, log::{LogLevel, LogMessage}, @@ -57,7 +67,7 @@ macro_rules! kinfo { macro_rules! kwarn { ($($arg:tt)*) => { $crate::libs::printk::Logger.log(4,format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); - $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::YELLOW, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ WARN ] "); + $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("\x1B[1;33m[ WARN ] \x1B[0m")); $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); } } @@ -66,7 +76,7 @@ macro_rules! kwarn { macro_rules! kerror { ($($arg:tt)*) => { $crate::libs::printk::Logger.log(3,format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); - $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ ERROR ] "); + $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("\x1B[41m[ ERROR ] \x1B[0m")); $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); } } @@ -75,7 +85,7 @@ macro_rules! kerror { macro_rules! kBUG { ($($arg:tt)*) => { $crate::libs::printk::Logger.log(1,format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); - $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ BUG ] "); + $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("\x1B[41m[ BUG ] \x1B[0m")); $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t {}\n", file!(), line!(),format_args!($($arg)*))); } } @@ -91,11 +101,21 @@ impl PrintkWriter { /// 并输出白底黑字 /// @param str: 要写入的字符 pub fn __write_string(&mut self, s: &str) { - textui_putstr(s, FontColor::WHITE, FontColor::BLACK).ok(); - } - - pub fn __write_string_color(&self, fr_color: FontColor, bk_color: FontColor, s: &str) { - textui_putstr(s, fr_color, bk_color).ok(); + let current_vcnum = CURRENT_VCNUM.load(Ordering::SeqCst); + if current_vcnum != -1 { + // tty已经初始化了之后才输出到屏幕 + let port = TTY_PORTS[current_vcnum as usize].clone(); + let tty = port.port_data().tty(); + if tty.is_some() { + let tty = tty.unwrap(); + let _ = tty.write(tty.core(), s.as_bytes(), s.len()); + send_to_default_serial8250_port(s.as_bytes()); + } else { + let _ = textui_putstr(s, FontColor::WHITE, FontColor::BLACK); + } + } else { + let _ = textui_putstr(s, FontColor::WHITE, FontColor::BLACK); + } } } diff --git a/kernel/src/mm/init.rs b/kernel/src/mm/init.rs index 1ad78550..b1b79fc9 100644 --- a/kernel/src/mm/init.rs +++ b/kernel/src/mm/init.rs @@ -1,7 +1,7 @@ use core::{fmt::Write, sync::atomic::Ordering}; use crate::{ - arch::MMArch, driver::tty::serial::serial8250::send_to_default_serial8250_port, + arch::MMArch, driver::serial::serial8250::send_to_default_serial8250_port, filesystem::procfs::kmsg::kmsg_init, libs::printk::PrintkWriter, mm::mmio_buddy::mmio_init, }; diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 5f29bb2b..4c5ed8cb 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -21,6 +21,7 @@ use crate::{ sched::sched, CurrentIrqArch, }, + driver::tty::tty_core::TtyCore, exception::InterruptArch, filesystem::{ procfs::procfs_unregister_pid, @@ -1302,6 +1303,8 @@ pub struct ProcessSignalInfo { sig_pending: SigPending, // sig_shared_pending 中存储当前线程所属进程要处理的信号 sig_shared_pending: SigPending, + // 当前进程对应的tty + tty: Option>, } impl ProcessSignalInfo { @@ -1329,6 +1332,14 @@ impl ProcessSignalInfo { &self.sig_shared_pending } + pub fn tty(&self) -> Option> { + self.tty.clone() + } + + pub fn set_tty(&mut self, tty: Arc) { + self.tty = Some(tty); + } + /// 从 pcb 的 siginfo中取出下一个要处理的信号,先处理线程信号,再处理进程信号 /// /// ## 参数 @@ -1351,6 +1362,7 @@ impl Default for ProcessSignalInfo { sig_block: SigSet::empty(), sig_pending: SigPending::default(), sig_shared_pending: SigPending::default(), + tty: None, } } } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 1a74881f..132768a2 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -12,6 +12,7 @@ use crate::{ process::{ fork::KernelCloneArgs, resource::{RLimit64, RUsage}, + ProcessManager, }, }; @@ -853,6 +854,11 @@ impl Syscall { Ok(0) } + SYS_SETPGID => { + kwarn!("SYS_SETPGID has not yet been implemented"); + Ok(0) + } + SYS_RT_SIGPROCMASK => { kwarn!("SYS_RT_SIGPROCMASK has not yet been implemented"); Ok(0) @@ -1009,6 +1015,19 @@ impl Syscall { Err(SystemError::ENOSYS) } + #[cfg(target_arch = "x86_64")] + SYS_GETRLIMIT => { + let resource = args[0]; + let rlimit = args[1] as *mut RLimit64; + + Self::prlimit64( + ProcessManager::current_pcb().pid(), + resource, + 0 as *const RLimit64, + rlimit, + ) + } + SYS_SCHED_YIELD => Self::sched_yield(), _ => panic!("Unsupported syscall ID: {}", syscall_num), diff --git a/kernel/src/virt/kvm/kvm_dev.rs b/kernel/src/virt/kvm/kvm_dev.rs index f0ca4320..b727a3d9 100644 --- a/kernel/src/virt/kvm/kvm_dev.rs +++ b/kernel/src/virt/kvm/kvm_dev.rs @@ -128,7 +128,12 @@ impl IndexNode for LockedKvmInode { /// /// @return 成功:Ok() /// 失败:Err(错误码) - fn ioctl(&self, cmd: u32, data: usize) -> Result { + fn ioctl( + &self, + cmd: u32, + data: usize, + _private_data: &FilePrivateData, + ) -> Result { match cmd { 0xdeadbeef => { kdebug!("kvm ioctl"); diff --git a/kernel/src/virt/kvm/vcpu_dev.rs b/kernel/src/virt/kvm/vcpu_dev.rs index 916587fa..84b9fc48 100644 --- a/kernel/src/virt/kvm/vcpu_dev.rs +++ b/kernel/src/virt/kvm/vcpu_dev.rs @@ -136,7 +136,12 @@ impl IndexNode for LockedVcpuInode { /// /// @return 成功:Ok() /// 失败:Err(错误码) - fn ioctl(&self, cmd: u32, data: usize) -> Result { + fn ioctl( + &self, + cmd: u32, + data: usize, + _private_data: &FilePrivateData, + ) -> Result { match cmd { 0xdeadbeef => { kdebug!("kvm_cpu ioctl"); diff --git a/kernel/src/virt/kvm/vm_dev.rs b/kernel/src/virt/kvm/vm_dev.rs index 4f311395..292cab3e 100644 --- a/kernel/src/virt/kvm/vm_dev.rs +++ b/kernel/src/virt/kvm/vm_dev.rs @@ -134,7 +134,12 @@ impl IndexNode for LockedVmInode { /// /// @return 成功:Ok() /// 失败:Err(错误码) - fn ioctl(&self, cmd: u32, data: usize) -> Result { + fn ioctl( + &self, + cmd: u32, + data: usize, + _private_data: &FilePrivateData, + ) -> Result { match cmd { 0xdeadbeef => { kdebug!("kvm_vm ioctl"); diff --git a/user/apps/clear/.gitignore b/user/apps/clear/.gitignore new file mode 100644 index 00000000..1ac35461 --- /dev/null +++ b/user/apps/clear/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +/install/ \ No newline at end of file diff --git a/user/apps/clear/Cargo.toml b/user/apps/clear/Cargo.toml new file mode 100644 index 00000000..d9cea3cc --- /dev/null +++ b/user/apps/clear/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "clear" +version = "0.1.0" +edition = "2021" +description = "clear screen" +authors = [ "GnoCiYeH " ] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] \ No newline at end of file diff --git a/user/apps/clear/Makefile b/user/apps/clear/Makefile new file mode 100644 index 00000000..0239a062 --- /dev/null +++ b/user/apps/clear/Makefile @@ -0,0 +1,56 @@ +TOOLCHAIN="+nightly-2023-08-15-x86_64-unknown-linux-gnu" +# RUSTFLAGS+="-C target-feature=+crt-static -C link-arg=-no-pie" + +ifdef DADK_CURRENT_BUILD_DIR +# 如果是在dadk中编译,那么安装到dadk的安装目录中 + INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR) +else +# 如果是在本地编译,那么安装到当前目录下的install目录中 + INSTALL_DIR = ./install +endif + +ifeq ($(ARCH), x86_64) + export RUST_TARGET=x86_64-unknown-linux-musl +else ifeq ($(ARCH), riscv64) + export RUST_TARGET=riscv64gc-unknown-linux-gnu +else +# 默认为x86_86,用于本地编译 + export RUST_TARGET=x86_64-unknown-linux-musl +endif + +run: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) + +build: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) + +clean: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) + +test: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) + +doc: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET) + +fmt: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt + +fmt-check: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check + +run-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release + +build-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release + +clean-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release + +test-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release + +.PHONY: install +install: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force diff --git a/user/apps/clear/README.md b/user/apps/clear/README.md new file mode 100644 index 00000000..0e62bbe8 --- /dev/null +++ b/user/apps/clear/README.md @@ -0,0 +1,7 @@ +# DragonOS Tty Clear + +清屏程序:clear指令 + +## 使用方法 + +1. 直接运行`clear`即可 diff --git a/user/apps/clear/src/main.rs b/user/apps/clear/src/main.rs new file mode 100644 index 00000000..c75b6975 --- /dev/null +++ b/user/apps/clear/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("\x1Bc"); +} diff --git a/user/dadk/config/clear-0.1.0.dadk b/user/dadk/config/clear-0.1.0.dadk new file mode 100644 index 00000000..161acd0f --- /dev/null +++ b/user/dadk/config/clear-0.1.0.dadk @@ -0,0 +1,22 @@ +{ + "name": "clear", + "version": "0.1.0", + "description": "清屏", + "task_type": { + "BuildFromSource": { + "Local": { + "path": "apps/clear" + } + } + }, + "depends": [], + "build": { + "build_command": "make install" + }, + "clean": { + "clean_command": "make clean" + }, + "install": { + "in_dragonos_path": "/" + } +}