xref: /DragonOS/kernel/src/driver/tty/tty_core.rs (revision 6046f77591cf23dc9cc53b68b25c0d74f94fa493)
1 use core::{
2     fmt::Debug,
3     sync::atomic::{AtomicBool, AtomicUsize},
4 };
5 
6 use alloc::{collections::LinkedList, string::String, sync::Arc, vec::Vec};
7 use system_error::SystemError;
8 
9 use crate::{
10     driver::serial::serial8250::send_to_default_serial8250_port,
11     libs::{
12         rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableGuard, RwLockWriteGuard},
13         spinlock::{SpinLock, SpinLockGuard},
14         wait_queue::EventWaitQueue,
15     },
16     mm::VirtAddr,
17     net::event_poll::{EPollEventType, EPollItem},
18     process::Pid,
19     syscall::user_access::{UserBufferReader, UserBufferWriter},
20 };
21 
22 use super::{
23     termios::{ControlMode, PosixTermios, Termios, TtySetTermiosOpt, WindowSize},
24     tty_driver::{TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation},
25     tty_ldisc::{
26         ntty::{NTtyData, NTtyLinediscipline},
27         TtyLineDiscipline,
28     },
29     tty_port::TtyPort,
30     virtual_terminal::{virtual_console::VirtualConsoleData, VIRT_CONSOLES},
31 };
32 
33 #[derive(Debug)]
34 pub struct TtyCore {
35     core: TtyCoreData,
36     /// 线路规程函数集
37     line_discipline: Arc<dyn TtyLineDiscipline>,
38 }
39 
40 impl TtyCore {
41     pub fn new(driver: Arc<TtyDriver>, index: usize) -> Arc<Self> {
42         let name = driver.tty_line_name(index);
43         let termios = driver.init_termios();
44         let core = TtyCoreData {
45             tty_driver: driver,
46             termios: RwLock::new(termios),
47             name,
48             flags: RwLock::new(TtyFlag::empty()),
49             count: AtomicUsize::new(0),
50             window_size: RwLock::new(WindowSize::default()),
51             read_wq: EventWaitQueue::new(),
52             write_wq: EventWaitQueue::new(),
53             port: RwLock::new(None),
54             index,
55             ctrl: SpinLock::new(TtyContorlInfo::default()),
56             closing: AtomicBool::new(false),
57             flow: SpinLock::new(TtyFlowState::default()),
58             link: None,
59             epitems: SpinLock::new(LinkedList::new()),
60         };
61 
62         return Arc::new(Self {
63             core,
64             line_discipline: Arc::new(NTtyLinediscipline {
65                 data: SpinLock::new(NTtyData::new()),
66             }),
67         });
68     }
69 
70     #[inline]
71     pub fn core(&self) -> &TtyCoreData {
72         return &self.core;
73     }
74 
75     #[inline]
76     pub fn ldisc(&self) -> Arc<dyn TtyLineDiscipline> {
77         self.line_discipline.clone()
78     }
79 
80     pub fn write_without_serial(&self, buf: &[u8], nr: usize) -> Result<usize, SystemError> {
81         self.core
82             .driver()
83             .driver_funcs()
84             .write(self.core(), buf, nr)
85     }
86 
87     pub fn reopen(&self) -> Result<(), SystemError> {
88         let tty_core = self.core();
89         let driver = tty_core.driver();
90 
91         if driver.tty_driver_type() == TtyDriverType::Pty
92             && driver.tty_driver_sub_type() == TtyDriverSubType::PtyMaster
93         {
94             return Err(SystemError::EIO);
95         }
96 
97         // if *tty_core.count.read() == 0 {
98         //     return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
99         // }
100 
101         // TODO 判断flags
102 
103         tty_core.add_count();
104 
105         Ok(())
106     }
107 
108     #[inline]
109     pub fn set_port(&self, port: Arc<dyn TtyPort>) {
110         *self.core.port.write() = Some(port);
111     }
112 
113     pub fn tty_start(&self) {
114         let mut flow = self.core.flow.lock_irqsave();
115         if !flow.stopped || flow.tco_stopped {
116             return;
117         }
118 
119         flow.stopped = false;
120         let _ = self.start(self.core());
121         self.tty_wakeup();
122     }
123 
124     pub fn tty_stop(&self) {
125         let mut flow = self.core.flow.lock_irqsave();
126         if flow.stopped {
127             return;
128         }
129         flow.stopped = true;
130 
131         let _ = self.stop(self.core());
132     }
133 
134     pub fn tty_wakeup(&self) {
135         if self.core.flags().contains(TtyFlag::DO_WRITE_WAKEUP) {
136             let _ = self.ldisc().write_wakeup(self.core());
137         }
138 
139         self.core()
140             .write_wq
141             .wakeup(EPollEventType::EPOLLOUT.bits() as u64);
142     }
143 
144     pub fn tty_mode_ioctl(tty: Arc<TtyCore>, cmd: u32, arg: usize) -> Result<usize, SystemError> {
145         let core = tty.core();
146         let real_tty = if core.driver().tty_driver_type() == TtyDriverType::Pty
147             && core.driver().tty_driver_sub_type() == TtyDriverSubType::PtyMaster
148         {
149             core.link().unwrap()
150         } else {
151             tty
152         };
153         match cmd {
154             TtyIoctlCmd::TCGETS => {
155                 let termios = PosixTermios::from_kernel_termios(*real_tty.core.termios());
156                 let mut user_writer = UserBufferWriter::new(
157                     VirtAddr::new(arg).as_ptr::<PosixTermios>(),
158                     core::mem::size_of::<PosixTermios>(),
159                     true,
160                 )?;
161 
162                 user_writer.copy_one_to_user(&termios, 0)?;
163                 return Ok(0);
164             }
165             TtyIoctlCmd::TCSETS => {
166                 return TtyCore::core_set_termios(
167                     real_tty,
168                     VirtAddr::new(arg),
169                     TtySetTermiosOpt::TERMIOS_OLD,
170                 );
171             }
172             TtyIoctlCmd::TCSETSW => {
173                 return TtyCore::core_set_termios(
174                     real_tty,
175                     VirtAddr::new(arg),
176                     TtySetTermiosOpt::TERMIOS_WAIT | TtySetTermiosOpt::TERMIOS_OLD,
177                 );
178             }
179             _ => {
180                 return Err(SystemError::ENOIOCTLCMD);
181             }
182         }
183     }
184 
185     pub fn core_set_termios(
186         tty: Arc<TtyCore>,
187         arg: VirtAddr,
188         opt: TtySetTermiosOpt,
189     ) -> Result<usize, SystemError> {
190         #[allow(unused_assignments)]
191         // TERMIOS_TERMIO下会用到
192         let mut tmp_termios = *tty.core().termios();
193 
194         if opt.contains(TtySetTermiosOpt::TERMIOS_TERMIO) {
195             todo!()
196         } else {
197             let user_reader = UserBufferReader::new(
198                 arg.as_ptr::<PosixTermios>(),
199                 core::mem::size_of::<PosixTermios>(),
200                 true,
201             )?;
202 
203             let mut term = PosixTermios::default();
204             user_reader.copy_one_from_user(&mut term, 0)?;
205 
206             tmp_termios = term.to_kernel_termios();
207         }
208 
209         if opt.contains(TtySetTermiosOpt::TERMIOS_FLUSH) {
210             let ld = tty.ldisc();
211             let _ = ld.flush_buffer(tty.clone());
212         }
213 
214         if opt.contains(TtySetTermiosOpt::TERMIOS_WAIT) {
215             // TODO
216         }
217 
218         TtyCore::set_termios_next(tty, tmp_termios)?;
219         Ok(0)
220     }
221 
222     pub fn set_termios_next(tty: Arc<TtyCore>, new_termios: Termios) -> Result<(), SystemError> {
223         let mut termios = tty.core().termios_write();
224 
225         let old_termios = *termios;
226         *termios = new_termios;
227         let tmp = termios.control_mode;
228         termios.control_mode ^= (tmp ^ old_termios.control_mode) & ControlMode::ADDRB;
229 
230         let ret = tty.set_termios(tty.clone(), old_termios);
231         if ret.is_err() {
232             termios.control_mode &= ControlMode::HUPCL | ControlMode::CREAD | ControlMode::CLOCAL;
233             termios.control_mode |= old_termios.control_mode
234                 & !(ControlMode::HUPCL | ControlMode::CREAD | ControlMode::CLOCAL);
235             termios.input_speed = old_termios.input_speed;
236             termios.output_speed = old_termios.output_speed;
237         }
238 
239         drop(termios);
240         let ld = tty.ldisc();
241         ld.set_termios(tty, Some(old_termios))?;
242 
243         Ok(())
244     }
245 }
246 
247 #[derive(Debug, Default)]
248 pub struct TtyContorlInfo {
249     /// 前台进程pid
250     pub session: Option<Pid>,
251     /// 前台进程组id
252     pub pgid: Option<Pid>,
253 
254     /// packet模式下使用,目前未用到
255     pub pktstatus: u8,
256     pub packet: bool,
257 }
258 
259 #[derive(Debug, Default)]
260 pub struct TtyCoreWriteData {
261     /// 写缓冲区
262     pub write_buf: Vec<u8>,
263     /// 写入数量
264     pub write_cnt: usize,
265 }
266 
267 #[derive(Debug, Default)]
268 pub struct TtyFlowState {
269     /// 表示流控是否被停止
270     pub stopped: bool,
271     /// 表示 TCO(Transmit Continuous Operation)流控是否被停止
272     pub tco_stopped: bool,
273 }
274 
275 #[derive(Debug)]
276 pub struct TtyCoreData {
277     tty_driver: Arc<TtyDriver>,
278     termios: RwLock<Termios>,
279     name: String,
280     flags: RwLock<TtyFlag>,
281     /// 在初始化时即确定不会更改,所以这里不用加锁
282     index: usize,
283     count: AtomicUsize,
284     /// 窗口大小
285     window_size: RwLock<WindowSize>,
286     /// 读等待队列
287     read_wq: EventWaitQueue,
288     /// 写等待队列
289     write_wq: EventWaitQueue,
290     /// 端口
291     port: RwLock<Option<Arc<dyn TtyPort>>>,
292     /// 前台进程
293     ctrl: SpinLock<TtyContorlInfo>,
294     /// 是否正在关闭
295     closing: AtomicBool,
296     /// 流控状态
297     flow: SpinLock<TtyFlowState>,
298     /// 链接tty
299     link: Option<Arc<TtyCore>>,
300     /// epitems
301     epitems: SpinLock<LinkedList<Arc<EPollItem>>>,
302 }
303 
304 impl TtyCoreData {
305     #[inline]
306     pub fn driver(&self) -> Arc<TtyDriver> {
307         self.tty_driver.clone()
308     }
309 
310     #[inline]
311     pub fn flow_irqsave(&self) -> SpinLockGuard<TtyFlowState> {
312         self.flow.lock_irqsave()
313     }
314 
315     #[inline]
316     pub fn port(&self) -> Option<Arc<dyn TtyPort>> {
317         self.port.read().clone()
318     }
319 
320     #[inline]
321     pub fn index(&self) -> usize {
322         self.index
323     }
324 
325     #[inline]
326     pub fn name(&self) -> String {
327         self.name.clone()
328     }
329 
330     #[inline]
331     pub fn flags(&self) -> TtyFlag {
332         *self.flags.read_irqsave()
333     }
334 
335     #[inline]
336     pub fn termios(&self) -> RwLockReadGuard<'_, Termios> {
337         self.termios.read_irqsave()
338     }
339 
340     #[inline]
341     pub fn termios_write(&self) -> RwLockWriteGuard<Termios> {
342         self.termios.write_irqsave()
343     }
344 
345     #[inline]
346     pub fn set_termios(&self, termios: Termios) {
347         let mut termios_guard = self.termios_write();
348         *termios_guard = termios;
349     }
350 
351     #[inline]
352     pub fn add_count(&self) {
353         self.count
354             .fetch_add(1, core::sync::atomic::Ordering::SeqCst);
355     }
356 
357     #[inline]
358     pub fn read_wq(&self) -> &EventWaitQueue {
359         &self.read_wq
360     }
361 
362     #[inline]
363     pub fn write_wq(&self) -> &EventWaitQueue {
364         &self.write_wq
365     }
366 
367     #[inline]
368     pub fn contorl_info_irqsave(&self) -> SpinLockGuard<TtyContorlInfo> {
369         self.ctrl.lock_irqsave()
370     }
371 
372     #[inline]
373     pub fn window_size_upgradeable(&self) -> RwLockUpgradableGuard<WindowSize> {
374         self.window_size.upgradeable_read()
375     }
376 
377     #[inline]
378     pub fn window_size(&self) -> RwLockReadGuard<WindowSize> {
379         self.window_size.read()
380     }
381 
382     #[inline]
383     pub fn is_closing(&self) -> bool {
384         self.closing.load(core::sync::atomic::Ordering::SeqCst)
385     }
386 
387     #[inline]
388     pub fn vc_data_irqsave(&self) -> SpinLockGuard<VirtualConsoleData> {
389         VIRT_CONSOLES[self.index].lock_irqsave()
390     }
391 
392     #[inline]
393     pub fn link(&self) -> Option<Arc<TtyCore>> {
394         self.link.clone()
395     }
396 
397     #[inline]
398     pub fn add_epitem(&self, epitem: Arc<EPollItem>) {
399         self.epitems.lock().push_back(epitem)
400     }
401 }
402 
403 /// TTY 核心接口,不同的tty需要各自实现这个trait
404 pub trait TtyCoreFuncs: Debug + Send + Sync {}
405 
406 impl TtyOperation for TtyCore {
407     #[inline]
408     fn open(&self, tty: &TtyCoreData) -> Result<(), SystemError> {
409         return self.core().tty_driver.driver_funcs().open(tty);
410     }
411 
412     #[inline]
413     fn write_room(&self, tty: &TtyCoreData) -> usize {
414         return self.core().tty_driver.driver_funcs().write_room(tty);
415     }
416 
417     #[inline]
418     fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError> {
419         send_to_default_serial8250_port(buf);
420         return self.core().tty_driver.driver_funcs().write(tty, buf, nr);
421     }
422 
423     #[inline]
424     fn flush_chars(&self, tty: &TtyCoreData) {
425         self.core().tty_driver.driver_funcs().flush_chars(tty);
426     }
427 
428     #[inline]
429     fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> {
430         return self.core().tty_driver.driver_funcs().put_char(tty, ch);
431     }
432 
433     #[inline]
434     fn install(&self, driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> {
435         return self.core().tty_driver.driver_funcs().install(driver, tty);
436     }
437 
438     #[inline]
439     fn start(&self, tty: &TtyCoreData) -> Result<(), SystemError> {
440         return self.core().tty_driver.driver_funcs().start(tty);
441     }
442 
443     #[inline]
444     fn stop(&self, tty: &TtyCoreData) -> Result<(), SystemError> {
445         return self.core().tty_driver.driver_funcs().stop(tty);
446     }
447 
448     #[inline]
449     fn ioctl(&self, tty: Arc<TtyCore>, cmd: u32, arg: usize) -> Result<(), SystemError> {
450         return self.core().tty_driver.driver_funcs().ioctl(tty, cmd, arg);
451     }
452 
453     #[inline]
454     fn chars_in_buffer(&self) -> usize {
455         return self.core().tty_driver.driver_funcs().chars_in_buffer();
456     }
457 
458     #[inline]
459     fn set_termios(&self, tty: Arc<TtyCore>, old_termios: Termios) -> Result<(), SystemError> {
460         return self
461             .core()
462             .tty_driver
463             .driver_funcs()
464             .set_termios(tty, old_termios);
465     }
466 }
467 
468 bitflags! {
469     pub struct TtyFlag: u32 {
470         /// 终端被节流
471         const THROTTLED		= 1 << 0;
472         /// 终端输入输出错误状态
473         const IO_ERROR		= 1 << 1;
474         /// 终端的其他一方已关闭
475         const OTHER_CLOSED	= 1 << 2;
476         /// 终端处于独占状态
477         const EXCLUSIVE		= 1 << 3;
478         /// 终端执行写唤醒操作
479         const DO_WRITE_WAKEUP	= 1 << 5;
480         /// 终端线路驱动程序已打开
481         const LDISC_OPEN		= 1 << 11;
482         /// 终端伪终端设备已锁定
483         const PTY_LOCK		= 1 << 16;
484         /// 终端禁用写分裂操作
485         const NO_WRITE_SPLIT	= 1 << 17;
486         /// 终端挂断(挂起)状态
487         const HUPPED		= 1 << 18;
488         /// 终端正在挂断(挂起)
489         const HUPPING		= 1 << 19;
490         /// 终端线路驱动程序正在更改
491         const LDISC_CHANGING	= 1 << 20;
492         /// 终端线路驱动程序已停止
493         const LDISC_HALTED	= 1 << 22;
494     }
495 }
496 
497 #[derive(Debug, PartialEq)]
498 pub enum EchoOperation {
499     /// 开始特殊操作。
500     Start,
501     /// 向后移动光标列。
502     MoveBackCol,
503     /// 设置规范模式下的列位置。
504     SetCanonCol,
505     /// 擦除制表符。
506     EraseTab,
507 
508     Undefined(u8),
509 }
510 
511 impl EchoOperation {
512     pub fn from_u8(num: u8) -> EchoOperation {
513         match num {
514             0xff => Self::Start,
515             0x80 => Self::MoveBackCol,
516             0x81 => Self::SetCanonCol,
517             0x82 => Self::EraseTab,
518             _ => Self::Undefined(num),
519         }
520     }
521 
522     pub fn to_u8(&self) -> u8 {
523         match *self {
524             EchoOperation::Start => 0xff,
525             EchoOperation::MoveBackCol => 0x80,
526             EchoOperation::SetCanonCol => 0x81,
527             EchoOperation::EraseTab => 0x82,
528             EchoOperation::Undefined(num) => num,
529         }
530     }
531 }
532 
533 pub struct TtyIoctlCmd;
534 
535 #[allow(dead_code)]
536 impl TtyIoctlCmd {
537     /// 获取终端参数
538     pub const TCGETS: u32 = 0x5401;
539     /// 设置终端参数
540     pub const TCSETS: u32 = 0x5402;
541     /// 设置终端参数并等待所有输出完成
542     pub const TCSETSW: u32 = 0x5403;
543     /// 设置终端参数并且等待所有输出完成,但在这之前将终端清空
544     pub const TCSETSF: u32 = 0x5404;
545     /// 获取终端参数
546     pub const TCGETA: u32 = 0x5405;
547     /// 设置终端参数
548     pub const TCSETA: u32 = 0x5406;
549     /// 设置终端参数并等待所有输出完成
550     pub const TCSETAW: u32 = 0x5407;
551     /// 设置终端参数并且等待所有输出完成,但在这之前将终端清空
552     pub const TCSETAF: u32 = 0x5408;
553     /// 发送零字节,等待所有输出完成
554     pub const TCSBRK: u32 = 0x5409;
555     /// 控制终端的流控
556     pub const TCXONC: u32 = 0x540A;
557     /// 刷新输入/输出缓冲区或者丢弃输入缓冲区
558     pub const TCFLSH: u32 = 0x540B;
559     /// 设置设备为独占模式
560     pub const TIOCEXCL: u32 = 0x540C;
561     /// 设置设备为非独占模式
562     pub const TIOCNXCL: u32 = 0x540D;
563     /// 设置当前进程的控制终端
564     pub const TIOCSCTTY: u32 = 0x540E;
565     /// 获取前台进程组
566     pub const TIOCGPGRP: u32 = 0x540F;
567     ///设置前台进程组
568     pub const TIOCSPGRP: u32 = 0x5410;
569     /// 获取输出队列的字节数
570     pub const TIOCOUTQ: u32 = 0x5411;
571     /// 模拟从终端输入字符
572     pub const TIOCSTI: u32 = 0x5412;
573     /// 获取窗口大小
574     pub const TIOCGWINSZ: u32 = 0x5413;
575     /// 设置窗口大小
576     pub const TIOCSWINSZ: u32 = 0x5414;
577     /// 获取终端控制信号的状态
578     pub const TIOCMGET: u32 = 0x5415;
579     /// 设置终端控制信号的位
580     pub const TIOCMBIS: u32 = 0x5416;
581     /// 清除终端控制信号的位
582     pub const TIOCMBIC: u32 = 0x5417;
583     /// 设置终端控制信号的状态
584     pub const TIOCMSET: u32 = 0x5418;
585     /// 获取软件载波状态
586     pub const TIOCGSOFTCAR: u32 = 0x5419;
587     /// 设置软件载波状态
588     pub const TIOCSSOFTCAR: u32 = 0x541A;
589     /// 获取输入队列的字节数
590     pub const FIONREAD: u32 = 0x541B;
591     /// Linux 特有命令
592     pub const TIOCLINUX: u32 = 0x541C;
593     /// 获取控制台设备
594     pub const TIOCCONS: u32 = 0x541D;
595     /// 获取串行设备参数
596     pub const TIOCGSERIAL: u32 = 0x541E;
597     /// 设置串行设备参数
598     pub const TIOCSSERIAL: u32 = 0x541F;
599     /// 设置套接字的报文模式
600     pub const TIOCPKT: u32 = 0x5420;
601     /// 设置非阻塞 I/O
602     pub const FIONBIO: u32 = 0x5421;
603     /// 清除控制终端
604     pub const TIOCNOTTY: u32 = 0x5422;
605     /// 设置终端线路驱动器
606     pub const TIOCSETD: u32 = 0x5423;
607     /// 获取终端线路驱动器
608     pub const TIOCGETD: u32 = 0x5424;
609     /// 发送终止条件
610     pub const TCSBRKP: u32 = 0x5425;
611     /// 开始发送零比特
612     pub const TIOCSBRK: u32 = 0x5427;
613     /// 停止发送零比特
614     pub const TIOCCBRK: u32 = 0x5428;
615     /// Return the session ID of FD
616     pub const TIOCGSID: u32 = 0x5429;
617 }
618