From d031d46fd9e9a62e8e975dba76e3bdef027f63b6 Mon Sep 17 00:00:00 2001 From: LoGin Date: Tue, 1 Oct 2024 11:35:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0serial=20console?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81non-graphic=E5=90=AF=E5=8A=A8=20(#94?= =?UTF-8?q?7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: longjin --- Makefile | 5 + docs/introduction/build_system.md | 1 + kernel/src/arch/x86_64/driver/apic/ioapic.rs | 2 +- kernel/src/arch/x86_64/interrupt/entry.rs | 1 - kernel/src/driver/serial/mod.rs | 38 +- kernel/src/driver/serial/serial8250/mod.rs | 72 +++- .../serial/serial8250/serial8250_pio.rs | 201 ++++++++++- kernel/src/driver/tty/console.rs | 13 +- kernel/src/driver/tty/kthread.rs | 10 +- kernel/src/driver/tty/pty/mod.rs | 2 + kernel/src/driver/tty/pty/unix98pty.rs | 2 +- kernel/src/driver/tty/termios.rs | 12 +- kernel/src/driver/tty/tty_core.rs | 58 ++- kernel/src/driver/tty/tty_device.rs | 45 +-- kernel/src/driver/tty/tty_driver.rs | 109 ++++-- kernel/src/driver/tty/tty_ldisc/ntty.rs | 3 +- kernel/src/driver/tty/tty_port.rs | 20 +- kernel/src/driver/tty/virtual_terminal/mod.rs | 334 ++++++++++++++---- .../tty/virtual_terminal/virtual_console.rs | 35 +- kernel/src/driver/video/console/dummycon.rs | 14 +- .../fbdev/base/fbcon/framebuffer_console.rs | 3 +- kernel/src/exception/manage.rs | 2 +- kernel/src/filesystem/devpts/mod.rs | 2 +- kernel/src/libs/lib_ui/textui.rs | 8 +- kernel/src/libs/printk.rs | 15 +- kernel/src/process/stdio.rs | 12 +- tools/run-qemu.sh | 53 +-- 27 files changed, 780 insertions(+), 292 deletions(-) diff --git a/Makefile b/Makefile index 293b6608..74a5dc5a 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,11 @@ write_diskimage-uefi: # 不编译,直接启动QEMU qemu: sh -c "cd tools && bash run-qemu.sh --bios=legacy --display=window && cd .." + +# 不编译,直接启动QEMU,不显示图像 +qemu-nographic: + sh -c "cd tools && bash run-qemu.sh --bios=legacy --display=nographic && cd .." + # 不编译,直接启动QEMU(UEFI) qemu-uefi: sh -c "cd tools && bash run-qemu.sh --bios=uefi --display=window && cd .." diff --git a/docs/introduction/build_system.md b/docs/introduction/build_system.md index f6098e91..ab0e76c8 100644 --- a/docs/introduction/build_system.md +++ b/docs/introduction/build_system.md @@ -242,6 +242,7 @@ make run-docker - Docker编译,并写入磁盘镜像,: `make docker` - Docker编译,写入磁盘镜像,并在QEMU中运行: `make run-docker` - 不编译,直接从已有的磁盘镜像启动: `make qemu` +- 不编译,直接从已有的磁盘镜像启动(无图形模式): `make qemu-nographic` - 清理编译产生的文件: `make clean` - 编译文档: `make docs` (需要手动安装sphinx以及docs下的`requirements.txt`中的依赖) - 清理文档: `make clean-docs` diff --git a/kernel/src/arch/x86_64/driver/apic/ioapic.rs b/kernel/src/arch/x86_64/driver/apic/ioapic.rs index b2b46b46..3149cf50 100644 --- a/kernel/src/arch/x86_64/driver/apic/ioapic.rs +++ b/kernel/src/arch/x86_64/driver/apic/ioapic.rs @@ -403,7 +403,7 @@ pub fn ioapic_init(ignore: &'static [IrqNumber]) { } // 绑定irqchip - for i in 32..256 { + for i in IoApic::VECTOR_BASE as u32..256 { let irq = IrqNumber::new(i); if ignore.contains(&irq) { diff --git a/kernel/src/arch/x86_64/interrupt/entry.rs b/kernel/src/arch/x86_64/interrupt/entry.rs index 3d8637a3..31e53a20 100644 --- a/kernel/src/arch/x86_64/interrupt/entry.rs +++ b/kernel/src/arch/x86_64/interrupt/entry.rs @@ -58,7 +58,6 @@ macro_rules! interrupt_handler { push rax mov rsi, {irqnum} jmp x86_64_do_irq - // jmp do_IRQ " ), irqnum = const($name), diff --git a/kernel/src/driver/serial/mod.rs b/kernel/src/driver/serial/mod.rs index 77bc956f..971d01a8 100644 --- a/kernel/src/driver/serial/mod.rs +++ b/kernel/src/driver/serial/mod.rs @@ -3,22 +3,27 @@ use core::{fmt::Debug, sync::atomic::AtomicU32}; use alloc::sync::Arc; use system_error::SystemError; -use crate::{driver::base::device::device_number::DeviceNumber, mm::VirtAddr}; +use crate::mm::VirtAddr; use self::serial8250::serial8250_manager; +use super::tty::{ + termios::{ControlMode, InputMode, LocalMode, OutputMode, Termios, INIT_CONTORL_CHARACTERS}, + tty_ldisc::LineDisciplineType, +}; + pub mod serial8250; #[allow(dead_code)] pub trait UartDriver: Debug + Send + Sync { - fn device_number(&self) -> DeviceNumber; - /// 获取最大的设备数量 fn max_devs_num(&self) -> i32; // todo: 获取指向console的指针(在我们系统里面,将来可能是改进后的Textui Window) } +pub const SERIAL_BAUDRATE: BaudRate = BaudRate::new(115200); + /// 串口端口应当实现的trait /// /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/serial_core.h#428 @@ -43,16 +48,41 @@ pub trait UartPort { int_like!(BaudRate, AtomicBaudRate, u32, AtomicU32); int_like!(DivisorFraction, u32); +lazy_static! { + pub static ref TTY_SERIAL_DEFAULT_TERMIOS: Termios = { + Termios { + input_mode: InputMode::ICRNL | InputMode::IXON | InputMode::IUTF8, + output_mode: OutputMode::OPOST | OutputMode::ONLCR, + control_mode: ControlMode::B115200 + | 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, + line: LineDisciplineType::NTty, + input_speed: SERIAL_BAUDRATE.data(), + output_speed: SERIAL_BAUDRATE.data(), + } + }; +} + #[inline(always)] #[allow(dead_code)] pub(super) fn uart_manager() -> &'static UartManager { &UartManager } - #[derive(Debug)] pub(super) struct UartManager; impl UartManager { + pub const NR_TTY_SERIAL_MAX: u32 = 128; /// todo: 把uart设备注册到tty层 /// /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/serial/serial_core.c?fi=uart_register_driver#2720 diff --git a/kernel/src/driver/serial/serial8250/mod.rs b/kernel/src/driver/serial/serial8250/mod.rs index 4f9577f8..257b4bc3 100644 --- a/kernel/src/driver/serial/serial8250/mod.rs +++ b/kernel/src/driver/serial/serial8250/mod.rs @@ -12,27 +12,35 @@ use log::error; use system_error::SystemError; use crate::{ - driver::base::{ - class::Class, - device::{ - bus::Bus, device_manager, device_number::DeviceNumber, driver::Driver, Device, - DeviceCommonData, DeviceKObjType, DeviceState, DeviceType, IdTable, - }, - kobject::{KObjType, KObject, KObjectCommonData, 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::Major, driver::Driver, Device, + DeviceCommonData, DeviceKObjType, DeviceState, DeviceType, IdTable, + }, + kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, + kset::KSet, + platform::{ + platform_device::{platform_device_manager, PlatformDevice}, + platform_driver::{platform_driver_manager, PlatformDriver}, + }, }, + tty::tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType}, }, filesystem::kernfs::KernFSInode, libs::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, }; -use self::serial8250_pio::{send_to_serial8250_pio_com1, serial8250_pio_port_early_init}; +#[cfg(target_arch = "x86_64")] +use self::serial8250_pio::{ + send_to_default_serial8250_pio_port, serial8250_pio_port_early_init, + serial_8250_pio_register_tty_devices, Serial8250PIOTtyDriverInner, +}; -use super::{uart_manager, UartDriver, UartPort}; +use super::{uart_manager, UartDriver, UartManager, UartPort, TTY_SERIAL_DEFAULT_TERMIOS}; +#[cfg(target_arch = "x86_64")] mod serial8250_pio; static mut SERIAL8250_ISA_DEVICES: Option> = None; @@ -62,6 +70,8 @@ static mut INITIALIZED: bool = false; pub(super) struct Serial8250Manager; impl Serial8250Manager { + pub const TTY_SERIAL_MINOR_START: u32 = 64; + /// 初始化串口设备(在内存管理初始化之前) pub fn early_init(&self) -> Result<(), SystemError> { // todo: riscv64: 串口设备初始化 @@ -109,6 +119,7 @@ impl Serial8250Manager { return e; })?; + self.serial_tty_init()?; unsafe { INITIALIZED = true; } @@ -116,6 +127,34 @@ impl Serial8250Manager { return Ok(()); } + #[cfg(target_arch = "riscv64")] + fn serial_tty_init(&self) -> Result<(), SystemError> { + Ok(()) + } + + #[cfg(target_arch = "x86_64")] + fn serial_tty_init(&self) -> Result<(), SystemError> { + let serial8250_tty_driver = TtyDriver::new( + UartManager::NR_TTY_SERIAL_MAX, + "ttyS", + 0, + Major::TTY_MAJOR, + Self::TTY_SERIAL_MINOR_START, + TtyDriverType::Serial, + *TTY_SERIAL_DEFAULT_TERMIOS, + Arc::new(Serial8250PIOTtyDriverInner::new()), + None, + ); + + TtyDriverManager::tty_register_driver(serial8250_tty_driver)?; + if let Err(e) = serial_8250_pio_register_tty_devices() { + if e != SystemError::ENODEV { + return Err(e); + } + } + Ok(()) + } + /// 把uart端口与uart driver、uart device绑定 /// /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/serial/8250/8250_core.c?r=&mo=30224&fi=1169#553 @@ -124,6 +163,7 @@ impl Serial8250Manager { uart_driver: &Arc, devs: &Arc, ) { + #[cfg(target_arch = "x86_64")] self.bind_pio_ports(uart_driver, devs); } @@ -394,10 +434,6 @@ impl Serial8250ISADriver { } impl UartDriver for Serial8250ISADriver { - fn device_number(&self) -> DeviceNumber { - todo!() - } - fn max_devs_num(&self) -> i32 { todo!() } @@ -522,7 +558,7 @@ impl KObject for Serial8250ISADriver { /// 临时函数,用于向默认的串口发送数据 pub fn send_to_default_serial8250_port(s: &[u8]) { #[cfg(target_arch = "x86_64")] - send_to_serial8250_pio_com1(s); + send_to_default_serial8250_pio_port(s); #[cfg(target_arch = "riscv64")] { diff --git a/kernel/src/driver/serial/serial8250/serial8250_pio.rs b/kernel/src/driver/serial/serial8250/serial8250_pio.rs index 54760ad9..0c346369 100644 --- a/kernel/src/driver/serial/serial8250/serial8250_pio.rs +++ b/kernel/src/driver/serial/serial8250/serial8250_pio.rs @@ -5,11 +5,33 @@ use core::{ sync::atomic::{AtomicBool, Ordering}, }; -use alloc::sync::{Arc, Weak}; +use alloc::{ + string::ToString, + sync::{Arc, Weak}, +}; use crate::{ - arch::{io::PortIOArch, CurrentPortIOArch}, - driver::serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort}, + arch::{driver::apic::ioapic::IoApic, io::PortIOArch, CurrentPortIOArch}, + driver::{ + base::device::{ + device_number::{DeviceNumber, Major}, + DeviceId, + }, + serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort}, + tty::{ + kthread::send_to_tty_refresh_thread, + termios::WindowSize, + tty_core::{TtyCore, TtyCoreData}, + tty_driver::{TtyDriver, TtyDriverManager, TtyOperation}, + virtual_terminal::{vc_manager, VirtConsole}, + }, + }, + exception::{ + irqdata::IrqHandlerData, + irqdesc::{IrqHandleFlags, IrqHandler, IrqReturn}, + manage::irq_manager, + IrqNumber, + }, libs::rwlock::RwLock, }; use system_error::SystemError; @@ -19,6 +41,8 @@ use super::{Serial8250ISADevices, Serial8250ISADriver, Serial8250Manager, Serial static mut PIO_PORTS: [Option; 8] = [None, None, None, None, None, None, None, None]; +const SERIAL_8250_PIO_IRQ: IrqNumber = IrqNumber::new(IoApic::VECTOR_BASE as u32 + 4); + impl Serial8250Manager { #[allow(static_mut_refs)] pub(super) fn bind_pio_ports( @@ -34,7 +58,7 @@ impl Serial8250Manager { } macro_rules! init_port { - ($port_num:expr, $baudrate:expr) => { + ($port_num:expr) => { unsafe { let port = Serial8250PIOPort::new( match $port_num { @@ -48,12 +72,17 @@ macro_rules! init_port { 8 => Serial8250PortBase::COM8, _ => panic!("invalid port number"), }, - BaudRate::new($baudrate), + crate::driver::serial::SERIAL_BAUDRATE, ); if let Ok(port) = port { if port.init().is_ok() { PIO_PORTS[$port_num - 1] = Some(port); + true + } else { + false } + } else { + false } } }; @@ -62,8 +91,9 @@ macro_rules! init_port { /// 在内存管理初始化之前,初始化串口设备 pub(super) fn serial8250_pio_port_early_init() -> Result<(), SystemError> { for i in 1..=8 { - init_port!(i, 115200); + init_port!(i); } + return Ok(()); } @@ -100,7 +130,6 @@ impl Serial8250PIOPort { } let port = self.iobase as u16; - unsafe { CurrentPortIOArch::out8(port + 1, 0x00); // Disable all interrupts self.set_divisor(self.baudrate.load(Ordering::SeqCst)) @@ -119,7 +148,9 @@ impl Serial8250PIOPort { // If serial is not faulty set it in normal operation mode // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) - CurrentPortIOArch::out8(port + 4, 0x08); + CurrentPortIOArch::out8(port + 4, 0x0b); + + CurrentPortIOArch::out8(port + 1, 0x01); // Enable interrupts } return Ok(()); @@ -168,13 +199,12 @@ impl Serial8250PIOPort { } } - /// 读取一个字节 - #[allow(dead_code)] - fn read_one_byte(&self) -> u8 { - while !self.serial_received() { - spin_loop(); + /// 读取一个字节,如果没有数据则返回None + fn read_one_byte(&self) -> Option { + if !self.serial_received() { + return None; } - return self.serial_in(0) as u8; + return Some(self.serial_in(0) as u8); } } @@ -235,7 +265,14 @@ impl UartPort for Serial8250PIOPort { } fn handle_irq(&self) -> Result<(), SystemError> { - todo!("serial8250_pio::handle_irq") + if let Some(c) = self.read_one_byte() { + send_to_tty_refresh_thread(&[c]); + } + Ok(()) + } + + fn iobase(&self) -> Option { + Some(self.iobase as usize) } } @@ -280,8 +317,140 @@ pub enum Serial8250PortBase { } /// 临时函数,用于向COM1发送数据 -pub fn send_to_serial8250_pio_com1(s: &[u8]) { +pub fn send_to_default_serial8250_pio_port(s: &[u8]) { if let Some(port) = unsafe { PIO_PORTS[0].as_ref() } { port.send_bytes(s); } } + +#[derive(Debug)] +pub(super) struct Serial8250PIOTtyDriverInner; + +impl Serial8250PIOTtyDriverInner { + pub fn new() -> Self { + Self + } + + fn do_install( + &self, + driver: Arc, + tty: Arc, + vc: Arc, + ) -> Result<(), SystemError> { + driver.standard_install(tty.clone())?; + vc.port().setup_internal_tty(Arc::downgrade(&tty)); + tty.set_port(vc.port()); + vc.devfs_setup()?; + + Ok(()) + } +} + +impl TtyOperation for Serial8250PIOTtyDriverInner { + fn open(&self, _tty: &TtyCoreData) -> Result<(), SystemError> { + Ok(()) + } + + fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result { + let index = tty.index(); + if tty.index() >= unsafe { PIO_PORTS.len() } { + return Err(SystemError::ENODEV); + } + let pio_port = unsafe { PIO_PORTS[index].as_ref() }.ok_or(SystemError::ENODEV)?; + pio_port.send_bytes(&buf[..nr]); + + Ok(nr) + } + + fn flush_chars(&self, _tty: &TtyCoreData) {} + + fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> { + self.write(tty, &[ch], 1).map(|_| ()) + } + + fn ioctl(&self, _tty: Arc, _cmd: u32, _arg: usize) -> Result<(), SystemError> { + Err(SystemError::ENOIOCTLCMD) + } + + fn close(&self, _tty: Arc) -> Result<(), SystemError> { + Ok(()) + } + + fn resize(&self, tty: Arc, winsize: WindowSize) -> Result<(), SystemError> { + *tty.core().window_size_write() = winsize; + Ok(()) + } + + fn install(&self, driver: Arc, tty: Arc) -> Result<(), SystemError> { + if tty.core().index() >= unsafe { PIO_PORTS.len() } { + return Err(SystemError::ENODEV); + } + let vc = VirtConsole::new(None); + let vc_index = vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?; + self.do_install(driver, tty, vc.clone()).inspect_err(|_| { + vc_manager().free(vc_index); + })?; + + Ok(()) + } +} + +pub(super) fn serial_8250_pio_register_tty_devices() -> Result<(), SystemError> { + let (_, driver) = TtyDriverManager::lookup_tty_driver(DeviceNumber::new( + Major::TTY_MAJOR, + Serial8250Manager::TTY_SERIAL_MINOR_START, + )) + .ok_or(SystemError::ENODEV)?; + + for (i, port) in unsafe { PIO_PORTS.iter() }.enumerate() { + if let Some(port) = port { + let core = driver.init_tty_device(Some(i)).inspect_err(|_| { + log::error!( + "failed to init tty device for serial 8250 pio port {}, port iobase: {:?}", + i, + port.iobase + ); + })?; + core.resize( core.clone(), WindowSize::DEFAULT) + .inspect_err(|_| { + log::error!( + "failed to resize tty device for serial 8250 pio port {}, port iobase: {:?}", + i, + port.iobase + ); + })?; + } + } + + irq_manager() + .request_irq( + SERIAL_8250_PIO_IRQ, + "serial8250_pio".to_string(), + &Serial8250IrqHandler, + IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_TRIGGER_RISING, + Some(DeviceId::new(Some("serial8250_pio"), None).unwrap()), + ) + .inspect_err(|e| { + log::error!("failed to request irq for serial 8250 pio: {:?}", e); + })?; + + Ok(()) +} + +#[derive(Debug)] +struct Serial8250IrqHandler; + +impl IrqHandler for Serial8250IrqHandler { + fn handle( + &self, + _irq: IrqNumber, + _static_data: Option<&dyn IrqHandlerData>, + _dynamic_data: Option>, + ) -> Result { + for port in unsafe { PIO_PORTS.iter() }.flatten() { + port.handle_irq()?; + } + + Ok(IrqReturn::Handled) + } +} diff --git a/kernel/src/driver/tty/console.rs b/kernel/src/driver/tty/console.rs index f127900d..1307f07d 100644 --- a/kernel/src/driver/tty/console.rs +++ b/kernel/src/driver/tty/console.rs @@ -1,13 +1,20 @@ +use alloc::sync::Arc; use system_error::SystemError; -use super::virtual_terminal::virtual_console::{ - CursorOperation, ScrollDir, VirtualConsoleData, VirtualConsoleIntensity, +use super::virtual_terminal::{ + virtual_console::{CursorOperation, ScrollDir, VirtualConsoleData, VirtualConsoleIntensity}, + VirtConsole, }; /// 终端切换相关的回调 pub trait ConsoleSwitch: Sync + Send { /// 初始化,会对vc_data进行一系列初始化操作 - fn con_init(&self, vc_data: &mut VirtualConsoleData, init: bool) -> Result<(), SystemError>; + fn con_init( + &self, + vc: &Arc, + vc_data: &mut VirtualConsoleData, + init: bool, + ) -> Result<(), SystemError>; /// 进行释放等系列操作,目前未使用 #[allow(dead_code)] diff --git a/kernel/src/driver/tty/kthread.rs b/kernel/src/driver/tty/kthread.rs index 243311c6..9016b0d1 100644 --- a/kernel/src/driver/tty/kthread.rs +++ b/kernel/src/driver/tty/kthread.rs @@ -5,7 +5,7 @@ use kdepends::thingbuf::StaticThingBuf; use crate::{ arch::CurrentIrqArch, - driver::tty::virtual_terminal::virtual_console::CURRENT_VCNUM, + driver::tty::virtual_terminal::vc_manager, exception::InterruptArch, process::{ kthread::{KernelThreadClosure, KernelThreadMechanism}, @@ -14,8 +14,6 @@ use crate::{ sched::{schedule, SchedMode}, }; -use super::tty_port::current_tty_port; - /// 用于缓存键盘输入的缓冲区 static KEYBUF: StaticThingBuf = StaticThingBuf::new(); @@ -51,8 +49,10 @@ fn tty_refresh_thread() -> i32 { *item = KEYBUF.pop().unwrap(); } - if CURRENT_VCNUM.load(core::sync::atomic::Ordering::SeqCst) != -1 { - let _ = current_tty_port().receive_buf(&data[0..to_dequeue], &[], to_dequeue); + if let Some(cur_vc) = vc_manager().current_vc() { + let _ = cur_vc + .port() + .receive_buf(&data[0..to_dequeue], &[], to_dequeue); } else { // 这里由于stdio未初始化,所以无法找到port // TODO: 考虑改用双端队列,能够将丢失的输入插回 diff --git a/kernel/src/driver/tty/pty/mod.rs b/kernel/src/driver/tty/pty/mod.rs index 751b02bb..99422c5a 100644 --- a/kernel/src/driver/tty/pty/mod.rs +++ b/kernel/src/driver/tty/pty/mod.rs @@ -253,6 +253,7 @@ pub fn pty_init() -> Result<(), SystemError> { TtyDriverType::Pty, *TTY_STD_TERMIOS, Arc::new(Unix98PtyDriverInner::new()), + None, ); ptm_driver.set_subtype(TtyDriverSubType::PtyMaster); let term = ptm_driver.init_termios_mut(); @@ -273,6 +274,7 @@ pub fn pty_init() -> Result<(), SystemError> { TtyDriverType::Pty, *TTY_STD_TERMIOS, Arc::new(Unix98PtyDriverInner::new()), + None, ); pts_driver.set_subtype(TtyDriverSubType::PtySlave); let term = pts_driver.init_termios_mut(); diff --git a/kernel/src/driver/tty/pty/unix98pty.rs b/kernel/src/driver/tty/pty/unix98pty.rs index 99bbab7b..c280f0b8 100644 --- a/kernel/src/driver/tty/pty/unix98pty.rs +++ b/kernel/src/driver/tty/pty/unix98pty.rs @@ -263,7 +263,7 @@ pub fn ptmx_open( let index = fsinfo.alloc_index()?; - let tty = TtyDriver::init_tty_device(ptm_driver(), index)?; + let tty = ptm_driver().init_tty_device(Some(index))?; // 设置privdata *data = FilePrivateData::Tty(TtyFilePrivateData { diff --git a/kernel/src/driver/tty/termios.rs b/kernel/src/driver/tty/termios.rs index e56d0ac7..b219d203 100644 --- a/kernel/src/driver/tty/termios.rs +++ b/kernel/src/driver/tty/termios.rs @@ -2,7 +2,7 @@ use super::tty_ldisc::LineDisciplineType; /// ## 窗口大小 #[repr(C)] -#[derive(Debug, Default, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct WindowSize { /// 行 pub row: u16, @@ -15,7 +15,8 @@ pub struct WindowSize { } impl WindowSize { - pub fn new(row: u16, col: u16, xpixel: u16, ypixel: u16) -> Self { + pub const DEFAULT: WindowSize = WindowSize::new(24, 80, 1, 1); + pub const fn new(row: u16, col: u16, xpixel: u16, ypixel: u16) -> Self { Self { row, col, @@ -25,6 +26,12 @@ impl WindowSize { } } +impl Default for WindowSize { + fn default() -> Self { + Self::DEFAULT + } +} + #[derive(Debug, Clone, Copy)] pub struct Termios { pub input_mode: InputMode, @@ -63,7 +70,6 @@ impl PosixTermios { } } - #[allow(dead_code)] pub fn to_kernel_termios(self) -> Termios { // TODO:这里没有考虑非规范模式 Termios { diff --git a/kernel/src/driver/tty/tty_core.rs b/kernel/src/driver/tty/tty_core.rs index 90da3be6..376de925 100644 --- a/kernel/src/driver/tty/tty_core.rs +++ b/kernel/src/driver/tty/tty_core.rs @@ -11,7 +11,7 @@ use alloc::{ use system_error::SystemError; use crate::{ - driver::{serial::serial8250::send_to_default_serial8250_port, tty::pty::ptm_driver}, + driver::{base::device::device_number::DeviceNumber, tty::pty::ptm_driver}, libs::{ rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableGuard, RwLockWriteGuard}, spinlock::{SpinLock, SpinLockGuard}, @@ -25,13 +25,13 @@ use crate::{ use super::{ termios::{ControlMode, PosixTermios, Termios, TtySetTermiosOpt, WindowSize}, - tty_driver::{TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation}, + tty_driver::{TtyCorePrivateField, TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation}, tty_ldisc::{ ntty::{NTtyData, NTtyLinediscipline}, TtyLineDiscipline, }, tty_port::TtyPort, - virtual_terminal::{virtual_console::VirtualConsoleData, VIRT_CONSOLES}, + virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData}, }; #[derive(Debug)] @@ -52,6 +52,9 @@ impl Drop for TtyCore { impl TtyCore { pub fn new(driver: Arc, index: usize) -> Arc { let name = driver.tty_line_name(index); + let device_number = driver + .device_number(index) + .expect("Get tty device number failed."); let termios = driver.init_termios(); let core = TtyCoreData { tty_driver: driver, @@ -64,11 +67,14 @@ impl TtyCore { write_wq: EventWaitQueue::new(), port: RwLock::new(None), index, + vc_index: AtomicUsize::new(usize::MAX), ctrl: SpinLock::new(TtyContorlInfo::default()), closing: AtomicBool::new(false), flow: SpinLock::new(TtyFlowState::default()), link: RwLock::default(), epitems: SpinLock::new(LinkedList::new()), + device_number, + privete_fields: SpinLock::new(None), }; return Arc::new(Self { @@ -84,6 +90,14 @@ impl TtyCore { return &self.core; } + pub fn private_fields(&self) -> Option> { + self.core.privete_fields.lock().clone() + } + + pub fn set_private_fields(&self, fields: Arc) { + *self.core.privete_fields.lock() = Some(fields); + } + #[inline] pub fn ldisc(&self) -> Arc { self.line_discipline.clone() @@ -231,7 +245,7 @@ impl TtyCore { Ok(0) } - pub fn set_termios_next(tty: Arc, new_termios: Termios) -> Result<(), SystemError> { + fn set_termios_next(tty: Arc, new_termios: Termios) -> Result<(), SystemError> { let mut termios = tty.core().termios_write(); let old_termios = *termios; @@ -252,7 +266,7 @@ impl TtyCore { drop(termios); let ld = tty.ldisc(); - ld.set_termios(tty, Some(old_termios))?; + ld.set_termios(tty, Some(old_termios)).ok(); Ok(()) } @@ -292,6 +306,7 @@ pub struct TtyCoreData { flags: RwLock, /// 在初始化时即确定不会更改,所以这里不用加锁 index: usize, + vc_index: AtomicUsize, count: AtomicUsize, /// 窗口大小 window_size: RwLock, @@ -311,12 +326,16 @@ pub struct TtyCoreData { link: RwLock>, /// epitems epitems: SpinLock>>, + /// 设备号 + device_number: DeviceNumber, + + privete_fields: SpinLock>>, } impl TtyCoreData { #[inline] - pub fn driver(&self) -> Arc { - self.tty_driver.clone() + pub fn driver(&self) -> &Arc { + &self.tty_driver } #[inline] @@ -335,8 +354,12 @@ impl TtyCoreData { } #[inline] - pub fn name(&self) -> String { - self.name.clone() + pub fn name(&self) -> &String { + &self.name + } + + pub fn device_number(&self) -> &DeviceNumber { + &self.device_number } #[inline] @@ -412,8 +435,20 @@ impl TtyCoreData { } #[inline] - pub fn vc_data_irqsave(&self) -> SpinLockGuard { - VIRT_CONSOLES[self.index].lock_irqsave() + pub fn vc_data(&self) -> Option>> { + vc_manager().get(self.vc_index()?).unwrap().vc_data() + } + + pub fn set_vc_index(&self, index: usize) { + self.vc_index.store(index, Ordering::SeqCst); + } + + pub fn vc_index(&self) -> Option { + let x = self.vc_index.load(Ordering::SeqCst); + if x == usize::MAX { + return None; + } + return Some(x); } #[inline] @@ -469,7 +504,6 @@ impl TtyOperation for TtyCore { #[inline] fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result { - send_to_default_serial8250_port(buf); return self.core().tty_driver.driver_funcs().write(tty, buf, nr); } diff --git a/kernel/src/driver/tty/tty_device.rs b/kernel/src/driver/tty/tty_device.rs index 61f40816..0185db9f 100644 --- a/kernel/src/driver/tty/tty_device.rs +++ b/kernel/src/driver/tty/tty_device.rs @@ -45,7 +45,7 @@ use super::{ sysfs::sys_class_tty_instance, termios::WindowSize, tty_core::{TtyCore, TtyFlag, TtyIoctlCmd}, - tty_driver::{TtyDriver, TtyDriverManager, TtyDriverSubType, TtyDriverType, TtyOperation}, + tty_driver::{TtyDriverManager, TtyDriverSubType, TtyDriverType, TtyOperation}, tty_job_control::TtyJobCtrlManager, virtual_terminal::vty_init, }; @@ -126,6 +126,10 @@ impl TtyDevice { pub fn inner_write(&self) -> RwLockWriteGuard { self.inner.write() } + + pub fn name_ref(&self) -> &str { + &self.name + } } impl IndexNode for TtyDevice { @@ -145,7 +149,7 @@ impl IndexNode for TtyDevice { let (index, driver) = TtyDriverManager::lookup_tty_driver(dev_num).ok_or(SystemError::ENODEV)?; - let tty = TtyDriver::open_tty(index, driver)?; + let tty = driver.open_tty(Some(index))?; // 设置privdata *data = FilePrivateData::Tty(TtyFilePrivateData { @@ -592,15 +596,6 @@ impl TtyFilePrivateData { #[unified_init(INITCALL_DEVICE)] #[inline(never)] pub fn tty_init() -> Result<(), SystemError> { - let tty = TtyDevice::new( - "tty0".to_string(), - IdTable::new( - String::from("tty0"), - Some(DeviceNumber::new(Major::TTY_MAJOR, 0)), - ), - TtyType::Tty, - ); - let console = TtyDevice::new( "console".to_string(), IdTable::new( @@ -610,34 +605,8 @@ pub fn tty_init() -> Result<(), SystemError> { TtyType::Tty, ); - // 注册tty设备 - // CharDevOps::cdev_add( - // tty.clone() as Arc, - // IdTable::new( - // String::from("tty0"), - // Some(DeviceNumber::new(Major::TTYAUX_MAJOR, 0)), - // ), - // 1, - // )?; - - // CharDevOps::register_chardev_region(DeviceNumber::new(Major::TTYAUX_MAJOR, 0), 1, "/dev/tty")?; - - // 注册console设备 - // CharDevOps::cdev_add( - // console.clone() as Arc, - // IdTable::new( - // String::from("console"), - // Some(DeviceNumber::new(Major::TTYAUX_MAJOR, 1)), - // ), - // 1, - // )?; - - // CharDevOps::register_chardev_region(DeviceNumber::new(Major::TTYAUX_MAJOR, 1), 1, "/dev/tty")?; - - // 将这两个设备注册到devfs,TODO:这里console设备应该与tty在一个设备group里面 - device_register(tty.clone())?; + // 将设备注册到devfs,TODO:这里console设备应该与tty在一个设备group里面 device_register(console.clone())?; - devfs_register(&tty.name.clone(), tty)?; devfs_register(&console.name.clone(), console)?; serial_init()?; diff --git a/kernel/src/driver/tty/tty_driver.rs b/kernel/src/driver/tty/tty_driver.rs index 6acb4cbd..fc86e63f 100644 --- a/kernel/src/driver/tty/tty_driver.rs +++ b/kernel/src/driver/tty/tty_driver.rs @@ -6,6 +6,7 @@ use alloc::{ vec::Vec, }; use hashbrown::HashMap; +use ida::IdAllocator; use log::warn; use system_error::SystemError; @@ -15,13 +16,17 @@ use crate::{ char::CharDevOps, device::{ device_number::{DeviceNumber, Major}, + device_register, driver::Driver, + IdTable, }, kobject::KObject, }, tty::tty_port::TtyPortState, }, + filesystem::devfs::devfs_register, libs::{ + lazy_init::Lazy, rwlock::RwLock, spinlock::{SpinLock, SpinLockGuard}, }, @@ -30,6 +35,7 @@ use crate::{ use super::{ termios::{Termios, WindowSize}, tty_core::{TtyCore, TtyCoreData}, + tty_device::TtyDevice, tty_ldisc::TtyLdiscManager, tty_port::{DefaultTtyPort, TtyPort}, }; @@ -79,6 +85,7 @@ impl TtyDriverManager { // 加入全局TtyDriver表 let driver = Arc::new(driver); + driver.self_ref.init(Arc::downgrade(&driver)); TTY_DRIVERS.lock().push(driver.clone()); // TODO: 加入procfs? @@ -87,6 +94,10 @@ impl TtyDriverManager { } } +/// tty 驱动程序的与设备相关的数据 +pub trait TtyDriverPrivateField: Debug + Send + Sync {} +pub trait TtyCorePrivateField: Debug + Send + Sync {} + #[allow(dead_code)] #[derive(Debug)] #[cast_to([sync] Driver)] @@ -121,7 +132,11 @@ pub struct TtyDriver { ttys: SpinLock>>, /// 管理的端口列表 ports: RwLock>>, - // procfs入口? + /// 与设备相关的私有数据 + private_field: Option>, + /// id分配器 + ida: SpinLock, + self_ref: Lazy>, } impl TtyDriver { @@ -135,6 +150,7 @@ impl TtyDriver { tty_driver_type: TtyDriverType, default_termios: Termios, driver_funcs: Arc, + private_field: Option>, ) -> Self { let mut ports: Vec> = Vec::with_capacity(count as usize); for _ in 0..count { @@ -156,6 +172,9 @@ impl TtyDriver { ttys: SpinLock::new(HashMap::new()), saved_termios: Vec::with_capacity(count as usize), ports: RwLock::new(ports), + private_field, + ida: SpinLock::new(IdAllocator::new(0, count as usize).unwrap()), + self_ref: Lazy::new(), } } @@ -179,6 +198,22 @@ impl TtyDriver { self.driver_funcs.clone() } + /// ## 获取该驱动对应的设备的设备号 + #[inline] + pub fn device_number(&self, index: usize) -> Option { + if index >= self.device_count as usize { + return None; + } + Some(DeviceNumber::new( + self.major, + self.minor_start + index as u32, + )) + } + + fn self_ref(&self) -> Arc { + self.self_ref.get().upgrade().unwrap() + } + #[inline] pub fn init_termios(&self) -> Termios { self.init_termios @@ -230,7 +265,7 @@ impl TtyDriver { ret.ok() } - fn standard_install(&self, tty_core: Arc) -> Result<(), SystemError> { + pub fn standard_install(&self, tty_core: Arc) -> Result<(), SystemError> { let tty = tty_core.core(); tty.init_termios(); // TODO:设置termios波特率? @@ -242,59 +277,81 @@ impl TtyDriver { Ok(()) } - fn driver_install_tty(driver: Arc, tty: Arc) -> Result<(), SystemError> { - let res = tty.install(driver.clone(), tty.clone()); + fn driver_install_tty(&self, tty: Arc) -> Result<(), SystemError> { + let res = tty.install(self.self_ref(), tty.clone()); if let Err(err) = res { if err == SystemError::ENOSYS { - return driver.standard_install(tty); + return self.standard_install(tty); } else { return Err(err); } } - driver.add_tty(tty); + self.add_tty(tty); Ok(()) } - pub fn init_tty_device( - driver: Arc, - index: usize, - ) -> Result, SystemError> { - let tty = TtyCore::new(driver.clone(), index); + pub fn init_tty_device(&self, index: Option) -> Result, SystemError> { + // 如果传入的index为None,那么就自动分配index + let idx: usize; + if let Some(i) = index { + if self.ida.lock().exists(i) { + return Err(SystemError::EINVAL); + } + idx = i; + } else { + idx = self.ida.lock().alloc().ok_or(SystemError::EBUSY)?; + } - Self::driver_install_tty(driver.clone(), tty.clone())?; + let tty = TtyCore::new(self.self_ref(), idx); + + self.driver_install_tty(tty.clone())?; let core = tty.core(); if core.port().is_none() { - let ports = driver.ports.read(); + let ports = self.ports.read(); ports[core.index()].setup_internal_tty(Arc::downgrade(&tty)); tty.set_port(ports[core.index()].clone()); } TtyLdiscManager::ldisc_setup(tty.clone(), tty.core().link())?; + // 在devfs创建对应的文件 + + let device = TtyDevice::new( + core.name().clone(), + IdTable::new(self.tty_line_name(idx), Some(*core.device_number())), + super::tty_device::TtyType::Tty, + ); + + devfs_register(device.name_ref(), device.clone())?; + device_register(device)?; Ok(tty) } /// ## 通过设备号找到对应驱动并且初始化Tty - pub fn open_tty(index: usize, driver: Arc) -> Result, SystemError> { - let tty = match driver.lookup_tty(index) { - Some(tty) => { - // TODO: 暂时这么写,因为还没写TtyPort - if tty.core().port().is_none() { - warn!("{} port is None", tty.core().name()); - } else if tty.core().port().unwrap().state() == TtyPortState::KOPENED { + pub fn open_tty(&self, index: Option) -> Result, SystemError> { + let mut tty: Option> = None; + + if index.is_some() { + if let Some(t) = self.lookup_tty(index.unwrap()) { + if t.core().port().is_none() { + warn!("{} port is None", t.core().name()); + } else if t.core().port().unwrap().state() == TtyPortState::KOPENED { return Err(SystemError::EBUSY); } - tty.reopen()?; - tty + t.reopen()?; + tty = Some(t); } - None => Self::init_tty_device(driver, index)?, - }; + } + if tty.is_none() { + tty = Some(self.init_tty_device(index)?); + } + let tty = tty.ok_or(SystemError::ENODEV)?; return Ok(tty); } @@ -447,7 +504,9 @@ pub trait TtyOperation: Sync + Send + Debug { fn close(&self, tty: Arc) -> Result<(), SystemError>; - fn resize(&self, _tty: Arc, _winsize: WindowSize) -> Result<(), SystemError>; + fn resize(&self, _tty: Arc, _winsize: WindowSize) -> Result<(), SystemError> { + Err(SystemError::ENOSYS) + } } #[allow(dead_code)] diff --git a/kernel/src/driver/tty/tty_ldisc/ntty.rs b/kernel/src/driver/tty/tty_ldisc/ntty.rs index 4f295806..8f2ed695 100644 --- a/kernel/src/driver/tty/tty_ldisc/ntty.rs +++ b/kernel/src/driver/tty/tty_ldisc/ntty.rs @@ -1209,7 +1209,8 @@ impl NTtyData { if termios.output_mode.contains(OutputMode::OCRNL) { break; } - self.canon_cursor_column = self.cursor_column; + self.cursor_column = 0; + self.canon_cursor_column = 0; } '\t' => { break; diff --git a/kernel/src/driver/tty/tty_port.rs b/kernel/src/driver/tty/tty_port.rs index 1a9097a1..b387343f 100644 --- a/kernel/src/driver/tty/tty_port.rs +++ b/kernel/src/driver/tty/tty_port.rs @@ -1,4 +1,4 @@ -use core::{fmt::Debug, sync::atomic::Ordering}; +use core::fmt::Debug; use alloc::sync::{Arc, Weak}; use kdepends::thingbuf::mpsc; @@ -6,26 +6,10 @@ use system_error::SystemError; use crate::libs::spinlock::{SpinLock, SpinLockGuard}; -use super::{ - tty_core::TtyCore, - virtual_terminal::{virtual_console::CURRENT_VCNUM, VIRT_CONSOLES}, -}; +use super::tty_core::TtyCore; const TTY_PORT_BUFSIZE: usize = 4096; -/// 获取当前tty port -#[inline] -pub fn current_tty_port() -> Arc { - VIRT_CONSOLES[CURRENT_VCNUM.load(Ordering::SeqCst) as usize] - .lock_irqsave() - .port() -} - -#[inline] -pub fn tty_port(index: usize) -> Arc { - VIRT_CONSOLES[index].lock_irqsave().port() -} - #[allow(dead_code)] #[derive(Debug)] pub struct TtyPortData { diff --git a/kernel/src/driver/tty/virtual_terminal/mod.rs b/kernel/src/driver/tty/virtual_terminal/mod.rs index f36bf7d4..62401b85 100644 --- a/kernel/src/driver/tty/virtual_terminal/mod.rs +++ b/kernel/src/driver/tty/virtual_terminal/mod.rs @@ -1,22 +1,28 @@ -use core::{fmt::Formatter, sync::atomic::Ordering}; +use core::fmt::Formatter; use alloc::{ string::{String, ToString}, sync::Arc, - vec::Vec, }; +use hashbrown::HashMap; +use ida::IdAllocator; use system_error::SystemError; +use unified_init::macros::unified_init; use crate::{ - driver::base::device::{ - device_number::{DeviceNumber, Major}, - device_register, IdTable, + driver::{ + base::device::{ + device_number::{DeviceNumber, Major}, + device_register, IdTable, + }, + serial::serial8250::send_to_default_serial8250_port, }, - filesystem::devfs::devfs_register, - libs::spinlock::SpinLock, + filesystem::devfs::{devfs_register, devfs_unregister}, + init::initcall::INITCALL_LATE, + libs::{lazy_init::Lazy, rwlock::RwLock, spinlock::SpinLock}, }; -use self::virtual_console::{VirtualConsoleData, CURRENT_VCNUM}; +use self::virtual_console::VirtualConsoleData; use super::{ console::ConsoleSwitch, @@ -24,12 +30,13 @@ use super::{ tty_core::{TtyCore, TtyCoreData}, tty_device::{TtyDevice, TtyType}, tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType, TtyOperation}, + tty_port::{DefaultTtyPort, TtyPort}, }; pub mod console_map; pub mod virtual_console; -pub const MAX_NR_CONSOLES: u32 = 63; +pub const MAX_NR_CONSOLES: u32 = 64; pub const VC_MAXCOL: usize = 32767; pub const VC_MAXROW: usize = 32767; @@ -48,14 +55,190 @@ pub const DEFAULT_BLUE: [u16; 16] = [ pub const COLOR_TABLE: &[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)))); + static ref VC_MANAGER: VirtConsoleManager = VirtConsoleManager::new(); +} + +/// 获取虚拟终端管理器 +#[inline] +pub fn vc_manager() -> &'static VirtConsoleManager { + &VC_MANAGER +} + +pub struct VirtConsole { + vc_data: Option>>, + port: Arc, + index: Lazy, + inner: SpinLock, +} + +struct InnerVirtConsole { + vcdev: Option>, +} + +impl VirtConsole { + pub fn new(vc_data: Option>>) -> Arc { + Arc::new(Self { + vc_data, + port: Arc::new(DefaultTtyPort::new()), + index: Lazy::new(), + inner: SpinLock::new(InnerVirtConsole { vcdev: None }), + }) + } + + pub fn vc_data(&self) -> Option>> { + self.vc_data.clone() + } + + pub fn port(&self) -> Arc { + self.port.clone() + } + + pub fn index(&self) -> Option { + self.index.try_get().cloned() + } + + pub fn devfs_setup(&self) -> Result<(), SystemError> { + let tty_core = self + .port + .port_data() + .internal_tty() + .ok_or(SystemError::ENODEV)?; + let tty_core_data = tty_core.core(); + let devnum = *tty_core_data.device_number(); + let vcname = format!("vc{}", self.index.get()); + + // 注册虚拟终端设备并将虚拟终端设备加入到文件系统 + let vcdev = TtyDevice::new( + vcname.clone(), + IdTable::new(vcname, Some(devnum)), + TtyType::Tty, + ); + + device_register(vcdev.clone())?; + devfs_register(vcdev.name_ref(), vcdev.clone())?; + tty_core_data.set_vc_index(*self.index.get()); + self.inner.lock().vcdev = Some(vcdev); + + Ok(()) + } + + fn devfs_remove(&self) { + let vcdev = self.inner.lock().vcdev.take(); + if let Some(vcdev) = vcdev { + devfs_unregister(vcdev.name_ref(), vcdev.clone()) + .inspect_err(|e| { + log::error!("virt console: devfs_unregister failed: {:?}", e); + }) + .ok(); + } + } +} + +struct InnerVirtConsoleManager { + consoles: HashMap>, + ida: IdAllocator, +} +pub struct VirtConsoleManager { + inner: SpinLock, + + current_vc: RwLock, usize)>>, +} + +impl VirtConsoleManager { + pub const DEFAULT_VC_NAMES: [&'static str; 4] = ["tty0", "ttyS0", "tty1", "ttyS1"]; + + pub fn new() -> Self { + let ida = IdAllocator::new(0, MAX_NR_CONSOLES as usize).unwrap(); + let consoles = HashMap::new(); + + Self { + inner: SpinLock::new(InnerVirtConsoleManager { consoles, ida }), + current_vc: RwLock::new(None), + } + } + + pub fn get(&self, index: usize) -> Option> { + let inner = self.inner.lock(); + inner.consoles.get(&index).cloned() + } + + pub fn alloc(&self, vc: Arc) -> Option { + let mut inner = self.inner.lock(); + let index = inner.ida.alloc()?; + vc.index.init(index); + if let Some(vc_data) = vc.vc_data.as_ref() { + vc_data.lock().vc_index = index; } - v - }; + inner.consoles.insert(index, vc); + Some(index) + } + + /// 释放虚拟终端 + pub fn free(&self, index: usize) { + let mut inner = self.inner.lock(); + if let Some(vc) = inner.consoles.remove(&index) { + vc.devfs_remove(); + } + inner.ida.free(index); + } + + /// 获取当前虚拟终端 + pub fn current_vc(&self) -> Option> { + self.current_vc.read().as_ref().map(|(vc, _)| vc.clone()) + } + + pub fn current_vc_index(&self) -> Option { + self.current_vc.read().as_ref().map(|(_, index)| *index) + } + + pub fn current_vc_tty_name(&self) -> Option { + self.current_vc() + .and_then(|vc| vc.port().port_data().internal_tty()) + .map(|tty| tty.core().name().to_string()) + } + + /// 设置当前虚拟终端 + pub fn set_current_vc(&self, vc: Arc) { + let index = *vc.index.get(); + *self.current_vc.write() = Some((vc, index)); + } + + /// 通过tty名称查找虚拟终端 + /// + /// # Arguments + /// + /// * `name` - tty名称 (如ttyS0) + pub fn lookup_vc_by_tty_name(&self, name: &str) -> Option> { + let inner = self.inner.lock(); + for (_index, vc) in inner.consoles.iter() { + let found = vc + .port + .port_data() + .internal_tty() + .map(|tty| tty.core().name().as_str() == name) + .unwrap_or(false); + + if found { + return Some(vc.clone()); + } + } + + None + } + + pub fn setup_default_vc(&self) { + // todo: 从内核启动参数中获取 + for name in Self::DEFAULT_VC_NAMES.iter() { + if let Some(vc) = self.lookup_vc_by_tty_name(name) { + log::info!("Set default vc with tty device: {}", name); + self.set_current_vc(vc); + return; + } + } + + panic!("virt console: setup default vc failed"); + } } #[derive(Debug, Clone, Copy, Default)] @@ -119,7 +302,8 @@ impl TtyConsoleDriverInner { fn do_write(&self, tty: &TtyCoreData, buf: &[u8], mut nr: usize) -> Result { // 关闭中断 - let mut vc_data = tty.vc_data_irqsave(); + let vc_data = tty.vc_data().unwrap(); + let mut vc_data_guard = vc_data.lock_irqsave(); let mut offset = 0; @@ -130,7 +314,7 @@ impl TtyConsoleDriverInner { let mut draw = DrawRegion::default(); // 首先隐藏光标再写 - vc_data.hide_cursor(); + vc_data_guard.hide_cursor(); while nr != 0 { if !rescan { @@ -139,7 +323,7 @@ impl TtyConsoleDriverInner { nr -= 1; } - let (tc, rescan_last) = vc_data.translate(&mut ch); + let (tc, rescan_last) = vc_data_guard.translate(&mut ch); if tc.is_none() { // 表示未转换完成 continue; @@ -148,30 +332,30 @@ impl TtyConsoleDriverInner { let tc = tc.unwrap(); rescan = rescan_last; - if vc_data.is_control(tc, ch) { - vc_data.flush(&mut draw); - vc_data.do_control(ch); + if vc_data_guard.is_control(tc, ch) { + vc_data_guard.flush(&mut draw); + vc_data_guard.do_control(ch); continue; } - if !vc_data.console_write_normal(tc, ch, &mut draw) { + if !vc_data_guard.console_write_normal(tc, ch, &mut draw) { continue; } } - vc_data.flush(&mut draw); + vc_data_guard.flush(&mut draw); // TODO: notify update return Ok(offset); } -} -impl TtyOperation for TtyConsoleDriverInner { - fn install(&self, _driver: Arc, tty: Arc) -> Result<(), SystemError> { + fn do_install(&self, tty: Arc, vc: &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)?; + let binding = vc.vc_data().unwrap(); + let mut vc_data = binding.lock(); + + self.console.con_init(vc, &mut vc_data, true)?; if vc_data.complement_mask == 0 { vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 }; } @@ -206,11 +390,24 @@ impl TtyOperation for TtyConsoleDriverInner { } // 设置tty的端口为vc端口 - vc_data.port().setup_internal_tty(Arc::downgrade(&tty)); - tty.set_port(vc_data.port()); + vc.port().setup_internal_tty(Arc::downgrade(&tty)); + tty.set_port(vc.port()); + vc.devfs_setup()?; // 加入sysfs? - CURRENT_VCNUM.store(tty_core.index() as isize, Ordering::SeqCst); + Ok(()) + } +} + +impl TtyOperation for TtyConsoleDriverInner { + fn install(&self, _driver: Arc, tty: Arc) -> Result<(), SystemError> { + let vc = VirtConsole::new(Some(Arc::new(SpinLock::new(VirtualConsoleData::new( + usize::MAX, + ))))); + vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?; + self.do_install(tty, &vc) + .inspect_err(|_| vc_manager().free(vc.index().unwrap()))?; + Ok(()) } @@ -228,6 +425,7 @@ impl TtyOperation for TtyConsoleDriverInner { // if String::from_utf8_lossy(buf) == "Hello world!\n" { // loop {} // } + send_to_default_serial8250_port(buf); let ret = self.do_write(tty, buf, nr); self.flush_chars(tty); ret @@ -235,8 +433,9 @@ impl TtyOperation for TtyConsoleDriverInner { #[inline(never)] fn flush_chars(&self, tty: &TtyCoreData) { - let mut vc_data = tty.vc_data_irqsave(); - vc_data.set_cursor(); + let vc_data = tty.vc_data().unwrap(); + let mut vc_data_guard = vc_data.lock_irqsave(); + vc_data_guard.set_cursor(); } fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> { @@ -295,49 +494,34 @@ pub struct DrawRegion { // 初始化虚拟终端 #[inline(never)] pub fn vty_init() -> Result<(), SystemError> { - // 注册虚拟终端设备并将虚拟终端设备加入到文件系统 - let vc0 = TtyDevice::new( - "vc0".to_string(), - IdTable::new( - String::from("vc0"), - Some(DeviceNumber::new(Major::TTY_MAJOR, 0)), - ), - TtyType::Tty, - ); - // 注册tty设备 - // CharDevOps::cdev_add( - // vc0.clone() as Arc, - // IdTable::new( - // String::from("vc0"), - // Some(DeviceNumber::new(Major::TTY_MAJOR, 0)), - // ), - // 1, - // )?; + if let Ok(tty_console_driver_inner) = TtyConsoleDriverInner::new() { + let console_driver = TtyDriver::new( + MAX_NR_CONSOLES, + "tty", + 0, + Major::TTY_MAJOR, + 0, + TtyDriverType::Console, + *TTY_STD_TERMIOS, + Arc::new(tty_console_driver_inner), + None, + ); - // 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, - Arc::new(TtyConsoleDriverInner::new()?), - ); - - TtyDriverManager::tty_register_driver(console_driver)?; - - CURRENT_VCNUM.store(0, Ordering::SeqCst); - - // 初始化键盘? - - // TODO: 为vc + TtyDriverManager::tty_register_driver(console_driver).inspect(|_| { + log::error!("tty console: register driver failed"); + })?; + } Ok(()) } + +#[unified_init(INITCALL_LATE)] +fn vty_late_init() -> Result<(), SystemError> { + let (_, console_driver) = + TtyDriverManager::lookup_tty_driver(DeviceNumber::new(Major::TTY_MAJOR, 0)) + .ok_or(SystemError::ENODEV)?; + console_driver.init_tty_device(None)?; + + vc_manager().setup_default_vc(); + Ok(()) +} diff --git a/kernel/src/driver/tty/virtual_terminal/virtual_console.rs b/kernel/src/driver/tty/virtual_terminal/virtual_console.rs index 992659c4..3b5630ed 100644 --- a/kernel/src/driver/tty/virtual_terminal/virtual_console.rs +++ b/kernel/src/driver/tty/virtual_terminal/virtual_console.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; +use core::sync::atomic::{AtomicBool, Ordering}; use alloc::{ sync::{Arc, Weak}, @@ -10,11 +10,7 @@ use log::warn; use crate::{ driver::{ serial::serial8250::send_to_default_serial8250_port, - tty::{ - console::ConsoleSwitch, - tty_port::{DefaultTtyPort, TtyPort}, - ConsoleFont, KDMode, - }, + tty::{console::ConsoleSwitch, ConsoleFont, KDMode}, }, libs::{font::FontDesc, rwlock::RwLock}, process::Pid, @@ -22,7 +18,8 @@ use crate::{ use super::{ console_map::{TranslationMap, TranslationMapType}, - Color, DrawRegion, VtMode, VtModeData, COLOR_TABLE, DEFAULT_BLUE, DEFAULT_GREEN, DEFAULT_RED, + vc_manager, Color, DrawRegion, VtMode, VtModeData, COLOR_TABLE, DEFAULT_BLUE, DEFAULT_GREEN, + DEFAULT_RED, }; pub(super) const NPAR: usize = 16; @@ -34,14 +31,12 @@ lazy_static! { } -pub static CURRENT_VCNUM: AtomicIsize = AtomicIsize::new(-1); - pub static CONSOLE_BLANKED: AtomicBool = AtomicBool::new(false); /// ## 虚拟控制台的信息 #[derive(Debug, Clone)] pub struct VirtualConsoleData { - pub num: usize, + pub vc_index: usize, pub state: VirtualConsoleInfo, pub saved_state: VirtualConsoleInfo, /// 最大列数 @@ -146,9 +141,6 @@ pub struct VirtualConsoleData { /// 对应的Console Driver funcs driver_funcs: Option>, - - /// 对应端口 - port: Arc, } impl VirtualConsoleData { @@ -210,16 +202,10 @@ impl VirtualConsoleData { screen_buf: Default::default(), driver_funcs: None, cursor_type: VcCursor::empty(), - num, - port: Arc::new(DefaultTtyPort::new()), + vc_index: num, } } - #[inline] - pub fn port(&self) -> Arc { - self.port.clone() - } - pub(super) fn init(&mut self, rows: Option, cols: Option, clear: bool) { if let Some(rows) = rows { self.rows = rows; @@ -245,12 +231,11 @@ impl VirtualConsoleData { } pub fn is_visible(&self) -> bool { - let cur_vc = CURRENT_VCNUM.load(Ordering::SeqCst); - if cur_vc == -1 { - return false; + if let Some(cur_vc) = vc_manager().current_vc_index() { + cur_vc == self.vc_index + } else { + false } - - cur_vc as usize == self.num } fn driver_funcs(&self) -> Arc { diff --git a/kernel/src/driver/video/console/dummycon.rs b/kernel/src/driver/video/console/dummycon.rs index abc78020..ec7244ab 100644 --- a/kernel/src/driver/video/console/dummycon.rs +++ b/kernel/src/driver/video/console/dummycon.rs @@ -5,7 +5,10 @@ use crate::driver::tty::{ console::ConsoleSwitch, termios::WindowSize, tty_driver::TtyOperation, - virtual_terminal::virtual_console::{CursorOperation, ScrollDir, VirtualConsoleData}, + virtual_terminal::{ + virtual_console::{CursorOperation, ScrollDir, VirtualConsoleData}, + VirtConsole, + }, }; lazy_static! { @@ -49,14 +52,19 @@ impl ConsoleSwitch for DummyConsole { ) -> Result { Ok(0) } - fn con_init(&self, vc_data: &mut VirtualConsoleData, init: bool) -> Result<(), SystemError> { + fn con_init( + &self, + vc: &Arc, + vc_data: &mut VirtualConsoleData, + init: bool, + ) -> Result<(), SystemError> { vc_data.color_mode = true; if init { vc_data.cols = Self::COLUNMS; vc_data.rows = Self::ROWS; } else { - let tty = vc_data.port().port_data().tty().unwrap(); + let tty = vc.port().port_data().tty().unwrap(); tty.resize( tty.clone(), WindowSize::new(Self::ROWS as u16, Self::COLUNMS as u16, 0, 0), diff --git a/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs b/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs index 4a193f28..730e5590 100644 --- a/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs +++ b/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs @@ -8,7 +8,7 @@ use crate::{ console::ConsoleSwitch, virtual_terminal::{ virtual_console::{CursorOperation, ScrollDir, VcCursor, VirtualConsoleData}, - Color, + Color, VirtConsole, }, }, video::fbdev::base::{ @@ -174,6 +174,7 @@ impl BlittingFbConsole { impl ConsoleSwitch for BlittingFbConsole { fn con_init( &self, + _vc: &Arc, vc_data: &mut VirtualConsoleData, init: bool, ) -> Result<(), system_error::SystemError> { diff --git a/kernel/src/exception/manage.rs b/kernel/src/exception/manage.rs index 85a47b33..851a4024 100644 --- a/kernel/src/exception/manage.rs +++ b/kernel/src/exception/manage.rs @@ -156,7 +156,7 @@ impl IrqManager { *action_guard.flags_mut() = flags; *action_guard.dev_id_mut() = dev_id; drop(action_guard); - debug!("to inner_setup_irq"); + debug!("to inner_setup_irq: {irq:?}"); return self.inner_setup_irq(irq, irqaction, desc); } diff --git a/kernel/src/filesystem/devpts/mod.rs b/kernel/src/filesystem/devpts/mod.rs index 0f0778e3..dae03024 100644 --- a/kernel/src/filesystem/devpts/mod.rs +++ b/kernel/src/filesystem/devpts/mod.rs @@ -50,7 +50,7 @@ impl DevPtsFs { let root_inode = Arc::new(LockedDevPtsFSInode::new()); let ret = Arc::new(Self { root_inode, - pts_ida: SpinLock::new(IdAllocator::new(1, NR_UNIX98_PTY_MAX as usize).unwrap()), + pts_ida: SpinLock::new(IdAllocator::new(0, NR_UNIX98_PTY_MAX as usize).unwrap()), pts_count: AtomicU32::new(0), }); diff --git a/kernel/src/libs/lib_ui/textui.rs b/kernel/src/libs/lib_ui/textui.rs index d04b64bb..75fca7ce 100644 --- a/kernel/src/libs/lib_ui/textui.rs +++ b/kernel/src/libs/lib_ui/textui.rs @@ -1,7 +1,6 @@ use crate::{ driver::{ - serial::serial8250::send_to_default_serial8250_port, - tty::{tty_port::tty_port, virtual_terminal::virtual_console::CURRENT_VCNUM}, + serial::serial8250::send_to_default_serial8250_port, tty::virtual_terminal::vc_manager, video::video_refresh_manager, }, libs::{ @@ -1031,8 +1030,7 @@ 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 { + if let Some(current_vc) = vc_manager().current_vc() { // tty已经初始化了之后才输出到屏幕 let fr = (fr_color & 0x00ff0000) >> 16; let fg = (fr_color & 0x0000ff00) >> 8; @@ -1044,7 +1042,7 @@ pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) "\x1B[38;2;{fr};{fg};{fb};48;2;{br};{bg};{bb}m{}\x1B[0m", character as char ); - let port = tty_port(current_vcnum as usize); + let port = current_vc.port(); let tty = port.port_data().internal_tty(); if let Some(tty) = tty { send_to_default_serial8250_port(&[character]); diff --git a/kernel/src/libs/printk.rs b/kernel/src/libs/printk.rs index 65f63004..7ba02602 100644 --- a/kernel/src/libs/printk.rs +++ b/kernel/src/libs/printk.rs @@ -1,7 +1,4 @@ -use core::{ - fmt::{self, Write}, - sync::atomic::Ordering, -}; +use core::fmt::{self, Write}; use alloc::string::ToString; use log::{info, Level, Log}; @@ -9,10 +6,7 @@ use log::{info, Level, Log}; use super::lib_ui::textui::{textui_putstr, FontColor}; use crate::{ - driver::tty::{ - tty_driver::TtyOperation, tty_port::tty_port, - virtual_terminal::virtual_console::CURRENT_VCNUM, - }, + driver::tty::{tty_driver::TtyOperation, virtual_terminal::vc_manager}, filesystem::procfs::{ kmsg::KMSG, log::{LogLevel, LogMessage}, @@ -44,10 +38,9 @@ impl PrintkWriter { /// 并输出白底黑字 /// @param str: 要写入的字符 pub fn __write_string(&mut self, s: &str) { - let current_vcnum = CURRENT_VCNUM.load(Ordering::SeqCst); - if current_vcnum != -1 { + if let Some(current_vc) = vc_manager().current_vc() { // tty已经初始化了之后才输出到屏幕 - let port = tty_port(current_vcnum as usize); + let port = current_vc.port(); let tty = port.port_data().internal_tty(); if let Some(tty) = tty { let _ = tty.write(tty.core(), s.as_bytes(), s.len()); diff --git a/kernel/src/process/stdio.rs b/kernel/src/process/stdio.rs index 50014508..af8dc88e 100644 --- a/kernel/src/process/stdio.rs +++ b/kernel/src/process/stdio.rs @@ -1,6 +1,7 @@ use system_error::SystemError; use crate::{ + driver::tty::virtual_terminal::vc_manager, filesystem::vfs::{ file::{File, FileMode}, ROOT_INODE, @@ -13,9 +14,16 @@ pub fn stdio_init() -> Result<(), SystemError> { if ProcessManager::current_pcb().pid() != Pid(1) { return Err(SystemError::EPERM); } + let tty_path = format!( + "/dev/{}", + vc_manager() + .current_vc_tty_name() + .expect("Init stdio: can't get tty name") + ); let tty_inode = ROOT_INODE() - .lookup("/dev/tty0") - .expect("Init stdio: can't find tty0"); + .lookup(&tty_path) + .unwrap_or_else(|_| panic!("Init stdio: can't find {}", tty_path)); + let stdin = File::new(tty_inode.clone(), FileMode::O_RDONLY).expect("Init stdio: can't create stdin"); let stdout = diff --git a/tools/run-qemu.sh b/tools/run-qemu.sh index ae65aa67..1023901e 100644 --- a/tools/run-qemu.sh +++ b/tools/run-qemu.sh @@ -77,6 +77,7 @@ QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none" QEMU_ACCELARATE="" QEMU_ARGUMENT="" QEMU_DEVICES="" +BIOS_TYPE="" #这个变量为true则使用virtio磁盘 VIRTIO_BLK_DEVICE=false # 如果qemu_accel不为空 @@ -109,6 +110,35 @@ if [ ${ARCH} == "riscv64" ]; then QEMU_SERIAL="" fi +while true;do + case "$1" in + --bios) + case "$2" in + uefi) #uefi启动新增ovmf.fd固件 + BIOS_TYPE=uefi + ;; + legacy) + BIOS_TYPE=legacy + ;; + esac;shift 2;; + --display) + case "$2" in + vnc) + QEMU_ARGUMENT+=" -display vnc=:00" + ;; + window) + ;; + nographic) + QEMU_SERIAL=" -serial mon:stdio " + QEMU_MONITOR="" + QEMU_ARGUMENT+=" --nographic " + + ;; + esac;shift 2;; + *) break + esac + done + # ps: 下面这条使用tap的方式,无法dhcp获取到ip,暂时不知道为什么 # QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -net nic,netdev=nic0 -netdev tap,id=nic0,model=virtio-net-pci,script=qemu/ifup-nat,downscript=qemu/ifdown-nat -usb -device qemu-xhci,id=xhci,p2=8,p3=4 " @@ -149,28 +179,7 @@ install_riscv_uboot() if [ $flag_can_run -eq 1 ]; then - while true;do - case "$1" in - --bios) - case "$2" in - uefi) #uefi启动新增ovmf.fd固件 - BIOS_TYPE=uefi - ;; - legacy) - BIOS_TYPE=legacy - ;; - esac;shift 2;; - --display) - case "$2" in - vnc) - QEMU_ARGUMENT+=" -display vnc=:00" - ;; - window) - ;; - esac;shift 2;; - *) break - esac - done + # 删除共享内存 sudo rm -rf ${QEMU_MEMORY_BACKEND_PATH_PREFIX}/${QEMU_MEMORY_BACKEND}