xref: /DragonOS/kernel/src/driver/tty/virtual_terminal/mod.rs (revision a8753f8fffb992e4d3bbd21eda431081b395af6b)
1 use core::fmt::Formatter;
2 
3 use alloc::{
4     string::{String, ToString},
5     sync::Arc,
6 };
7 use hashbrown::HashMap;
8 use ida::IdAllocator;
9 use system_error::SystemError;
10 use unified_init::macros::unified_init;
11 
12 use crate::{
13     driver::{
14         base::device::{
15             device_number::{DeviceNumber, Major},
16             device_register, IdTable,
17         },
18         serial::serial8250::send_to_default_serial8250_port,
19     },
20     filesystem::devfs::{devfs_register, devfs_unregister},
21     init::initcall::INITCALL_LATE,
22     libs::{lazy_init::Lazy, rwlock::RwLock, spinlock::SpinLock},
23 };
24 
25 use self::virtual_console::VirtualConsoleData;
26 
27 use super::{
28     console::ConsoleSwitch,
29     termios::{InputMode, TTY_STD_TERMIOS},
30     tty_core::{TtyCore, TtyCoreData},
31     tty_device::{TtyDevice, TtyType},
32     tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType, TtyOperation},
33     tty_port::{DefaultTtyPort, TtyPort},
34 };
35 
36 pub mod console_map;
37 pub mod virtual_console;
38 
39 pub const MAX_NR_CONSOLES: u32 = 64;
40 pub const VC_MAXCOL: usize = 32767;
41 pub const VC_MAXROW: usize = 32767;
42 
43 pub const DEFAULT_RED: [u16; 16] = [
44     0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff,
45 ];
46 
47 pub const DEFAULT_GREEN: [u16; 16] = [
48     0x00, 0x00, 0xaa, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff,
49 ];
50 
51 pub const DEFAULT_BLUE: [u16; 16] = [
52     0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff,
53 ];
54 
55 pub const COLOR_TABLE: &[u8] = &[0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15];
56 
57 lazy_static! {
58     static ref VC_MANAGER: VirtConsoleManager = VirtConsoleManager::new();
59 }
60 
61 /// 获取虚拟终端管理器
62 #[inline]
63 pub fn vc_manager() -> &'static VirtConsoleManager {
64     &VC_MANAGER
65 }
66 
67 pub struct VirtConsole {
68     vc_data: Option<Arc<SpinLock<VirtualConsoleData>>>,
69     port: Arc<dyn TtyPort>,
70     index: Lazy<usize>,
71     inner: SpinLock<InnerVirtConsole>,
72 }
73 
74 struct InnerVirtConsole {
75     vcdev: Option<Arc<TtyDevice>>,
76 }
77 
78 impl VirtConsole {
79     pub fn new(vc_data: Option<Arc<SpinLock<VirtualConsoleData>>>) -> Arc<Self> {
80         Arc::new(Self {
81             vc_data,
82             port: Arc::new(DefaultTtyPort::new()),
83             index: Lazy::new(),
84             inner: SpinLock::new(InnerVirtConsole { vcdev: None }),
85         })
86     }
87 
88     pub fn vc_data(&self) -> Option<Arc<SpinLock<VirtualConsoleData>>> {
89         self.vc_data.clone()
90     }
91 
92     pub fn port(&self) -> Arc<dyn TtyPort> {
93         self.port.clone()
94     }
95 
96     pub fn index(&self) -> Option<usize> {
97         self.index.try_get().cloned()
98     }
99 
100     pub fn devfs_setup(&self) -> Result<(), SystemError> {
101         let tty_core = self
102             .port
103             .port_data()
104             .internal_tty()
105             .ok_or(SystemError::ENODEV)?;
106         let tty_core_data = tty_core.core();
107         let devnum = *tty_core_data.device_number();
108         let vcname = format!("vc{}", self.index.get());
109 
110         // 注册虚拟终端设备并将虚拟终端设备加入到文件系统
111         let vcdev = TtyDevice::new(
112             vcname.clone(),
113             IdTable::new(vcname, Some(devnum)),
114             TtyType::Tty,
115         );
116 
117         device_register(vcdev.clone())?;
118         devfs_register(vcdev.name_ref(), vcdev.clone())?;
119         tty_core_data.set_vc_index(*self.index.get());
120         self.inner.lock().vcdev = Some(vcdev);
121 
122         Ok(())
123     }
124 
125     fn devfs_remove(&self) {
126         let vcdev = self.inner.lock().vcdev.take();
127         if let Some(vcdev) = vcdev {
128             devfs_unregister(vcdev.name_ref(), vcdev.clone())
129                 .inspect_err(|e| {
130                     log::error!("virt console: devfs_unregister failed: {:?}", e);
131                 })
132                 .ok();
133         }
134     }
135 }
136 
137 struct InnerVirtConsoleManager {
138     consoles: HashMap<usize, Arc<VirtConsole>>,
139     ida: IdAllocator,
140 }
141 pub struct VirtConsoleManager {
142     inner: SpinLock<InnerVirtConsoleManager>,
143 
144     current_vc: RwLock<Option<(Arc<VirtConsole>, usize)>>,
145 }
146 
147 impl VirtConsoleManager {
148     pub const DEFAULT_VC_NAMES: [&'static str; 4] = ["tty0", "ttyS0", "tty1", "ttyS1"];
149 
150     pub fn new() -> Self {
151         let ida = IdAllocator::new(0, MAX_NR_CONSOLES as usize).unwrap();
152         let consoles = HashMap::new();
153 
154         Self {
155             inner: SpinLock::new(InnerVirtConsoleManager { consoles, ida }),
156             current_vc: RwLock::new(None),
157         }
158     }
159 
160     pub fn get(&self, index: usize) -> Option<Arc<VirtConsole>> {
161         let inner = self.inner.lock();
162         inner.consoles.get(&index).cloned()
163     }
164 
165     pub fn alloc(&self, vc: Arc<VirtConsole>) -> Option<usize> {
166         let mut inner = self.inner.lock();
167         let index = inner.ida.alloc()?;
168         vc.index.init(index);
169         if let Some(vc_data) = vc.vc_data.as_ref() {
170             vc_data.lock().vc_index = index;
171         }
172 
173         inner.consoles.insert(index, vc);
174         Some(index)
175     }
176 
177     /// 释放虚拟终端
178     pub fn free(&self, index: usize) {
179         let mut inner = self.inner.lock();
180         if let Some(vc) = inner.consoles.remove(&index) {
181             vc.devfs_remove();
182         }
183         inner.ida.free(index);
184     }
185 
186     /// 获取当前虚拟终端
187     pub fn current_vc(&self) -> Option<Arc<VirtConsole>> {
188         self.current_vc.read().as_ref().map(|(vc, _)| vc.clone())
189     }
190 
191     pub fn current_vc_index(&self) -> Option<usize> {
192         self.current_vc.read().as_ref().map(|(_, index)| *index)
193     }
194 
195     pub fn current_vc_tty_name(&self) -> Option<String> {
196         self.current_vc()
197             .and_then(|vc| vc.port().port_data().internal_tty())
198             .map(|tty| tty.core().name().to_string())
199     }
200 
201     /// 设置当前虚拟终端
202     pub fn set_current_vc(&self, vc: Arc<VirtConsole>) {
203         let index = *vc.index.get();
204         *self.current_vc.write() = Some((vc, index));
205     }
206 
207     /// 通过tty名称查找虚拟终端
208     ///
209     /// # Arguments
210     ///
211     /// * `name` - tty名称 (如ttyS0)
212     pub fn lookup_vc_by_tty_name(&self, name: &str) -> Option<Arc<VirtConsole>> {
213         let inner = self.inner.lock();
214         for (_index, vc) in inner.consoles.iter() {
215             let found = vc
216                 .port
217                 .port_data()
218                 .internal_tty()
219                 .map(|tty| tty.core().name().as_str() == name)
220                 .unwrap_or(false);
221 
222             if found {
223                 return Some(vc.clone());
224             }
225         }
226 
227         None
228     }
229 
230     pub fn setup_default_vc(&self) {
231         // todo: 从内核启动参数中获取
232         for name in Self::DEFAULT_VC_NAMES.iter() {
233             if let Some(vc) = self.lookup_vc_by_tty_name(name) {
234                 log::info!("Set default vc with tty device: {}", name);
235                 self.set_current_vc(vc);
236                 return;
237             }
238         }
239 
240         panic!("virt console: setup default vc failed");
241     }
242 }
243 
244 #[derive(Debug, Clone, Copy, Default)]
245 pub struct Color {
246     pub red: u16,
247     pub green: u16,
248     pub blue: u16,
249     pub transp: u16,
250 }
251 
252 impl Color {
253     pub fn from_256(col: u32) -> Self {
254         let mut color = Self::default();
255         if col < 8 {
256             color.red = if col & 1 != 0 { 0xaa } else { 0x00 };
257             color.green = if col & 2 != 0 { 0xaa } else { 0x00 };
258             color.blue = if col & 4 != 0 { 0xaa } else { 0x00 };
259         } else if col < 16 {
260             color.red = if col & 1 != 0 { 0xff } else { 0x55 };
261             color.green = if col & 2 != 0 { 0xff } else { 0x55 };
262             color.blue = if col & 4 != 0 { 0xff } else { 0x55 };
263         } else if col < 232 {
264             color.red = ((col - 16) / 36 * 85 / 2) as u16;
265             color.green = ((col - 16) / 6 % 6 * 85 / 2) as u16;
266             color.blue = ((col - 16) % 6 * 85 / 2) as u16;
267         } else {
268             let col = (col * 10 - 2312) as u16;
269             color.red = col;
270             color.green = col;
271             color.blue = col;
272         }
273 
274         color
275     }
276 }
277 
278 pub struct TtyConsoleDriverInner {
279     console: Arc<dyn ConsoleSwitch>,
280 }
281 
282 impl core::fmt::Debug for TtyConsoleDriverInner {
283     fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
284         write!(f, "TtyConsoleDriverInner")
285     }
286 }
287 
288 impl TtyConsoleDriverInner {
289     pub fn new() -> Result<Self, SystemError> {
290         let console = {
291             #[cfg(not(target_arch = "riscv64"))]
292             {
293                 Arc::new(crate::driver::video::fbdev::base::fbcon::framebuffer_console::BlittingFbConsole::new()?)
294             }
295 
296             #[cfg(target_arch = "riscv64")]
297             crate::driver::video::console::dummycon::dummy_console()
298         };
299 
300         Ok(Self { console })
301     }
302 
303     fn do_write(&self, tty: &TtyCoreData, buf: &[u8], mut nr: usize) -> Result<usize, SystemError> {
304         // 关闭中断
305         let vc_data = tty.vc_data().unwrap();
306         let mut vc_data_guard = vc_data.lock_irqsave();
307 
308         let mut offset = 0;
309 
310         // 这个参数是用来扫描unicode字符的,但是这部分目前未完成,先写着
311         let mut rescan = false;
312         let mut ch: u32 = 0;
313 
314         let mut draw = DrawRegion::default();
315 
316         // 首先隐藏光标再写
317         vc_data_guard.hide_cursor();
318 
319         while nr != 0 {
320             if !rescan {
321                 ch = buf[offset] as u32;
322                 offset += 1;
323                 nr -= 1;
324             }
325 
326             let (tc, rescan_last) = vc_data_guard.translate(&mut ch);
327             if tc.is_none() {
328                 // 表示未转换完成
329                 continue;
330             }
331 
332             let tc = tc.unwrap();
333             rescan = rescan_last;
334 
335             if vc_data_guard.is_control(tc, ch) {
336                 vc_data_guard.flush(&mut draw);
337                 vc_data_guard.do_control(ch);
338                 continue;
339             }
340 
341             if !vc_data_guard.console_write_normal(tc, ch, &mut draw) {
342                 continue;
343             }
344         }
345 
346         vc_data_guard.flush(&mut draw);
347 
348         // TODO: notify update
349         return Ok(offset);
350     }
351 
352     fn do_install(&self, tty: Arc<TtyCore>, vc: &Arc<VirtConsole>) -> Result<(), SystemError> {
353         let tty_core = tty.core();
354 
355         let binding = vc.vc_data().unwrap();
356         let mut vc_data = binding.lock();
357 
358         self.console.con_init(vc, &mut vc_data, true)?;
359         if vc_data.complement_mask == 0 {
360             vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 };
361         }
362         vc_data.s_complement_mask = vc_data.complement_mask;
363         // vc_data.bytes_per_row = vc_data.cols << 1;
364         vc_data.index = tty_core.index();
365         vc_data.bottom = vc_data.rows;
366         vc_data.set_driver_funcs(Arc::downgrade(
367             &(self.console.clone() as Arc<dyn ConsoleSwitch>),
368         ));
369 
370         // todo: unicode字符集处理?
371 
372         if vc_data.cols > VC_MAXCOL || vc_data.rows > VC_MAXROW {
373             return Err(SystemError::EINVAL);
374         }
375 
376         vc_data.init(None, None, true);
377         vc_data.update_attr();
378 
379         let window_size = tty_core.window_size_upgradeable();
380         if window_size.col == 0 && window_size.row == 0 {
381             let mut window_size = window_size.upgrade();
382             window_size.col = vc_data.cols as u16;
383             window_size.row = vc_data.rows as u16;
384         }
385 
386         if vc_data.utf {
387             tty_core.termios_write().input_mode.insert(InputMode::IUTF8);
388         } else {
389             tty_core.termios_write().input_mode.remove(InputMode::IUTF8);
390         }
391 
392         // 设置tty的端口为vc端口
393         vc.port().setup_internal_tty(Arc::downgrade(&tty));
394         tty.set_port(vc.port());
395         vc.devfs_setup()?;
396         // 加入sysfs?
397 
398         Ok(())
399     }
400 }
401 
402 impl TtyOperation for TtyConsoleDriverInner {
403     fn install(&self, _driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> {
404         let vc = VirtConsole::new(Some(Arc::new(SpinLock::new(VirtualConsoleData::new(
405             usize::MAX,
406         )))));
407         vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?;
408         self.do_install(tty, &vc)
409             .inspect_err(|_| vc_manager().free(vc.index().unwrap()))?;
410 
411         Ok(())
412     }
413 
414     fn open(&self, _tty: &TtyCoreData) -> Result<(), SystemError> {
415         Ok(())
416     }
417 
418     fn write_room(&self, _tty: &TtyCoreData) -> usize {
419         32768
420     }
421 
422     /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/vt/vt.c#2894
423     #[inline(never)]
424     fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError> {
425         // if String::from_utf8_lossy(buf) == "Hello world!\n" {
426         //     loop {}
427         // }
428         send_to_default_serial8250_port(buf);
429         let ret = self.do_write(tty, buf, nr);
430         self.flush_chars(tty);
431         ret
432     }
433 
434     #[inline(never)]
435     fn flush_chars(&self, tty: &TtyCoreData) {
436         let vc_data = tty.vc_data().unwrap();
437         let mut vc_data_guard = vc_data.lock_irqsave();
438         vc_data_guard.set_cursor();
439     }
440 
441     fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> {
442         self.write(tty, &[ch], 1)?;
443         Ok(())
444     }
445 
446     fn ioctl(&self, _tty: Arc<TtyCore>, _cmd: u32, _arg: usize) -> Result<(), SystemError> {
447         // TODO
448         Err(SystemError::ENOIOCTLCMD)
449     }
450 
451     fn close(&self, _tty: Arc<TtyCore>) -> Result<(), SystemError> {
452         Ok(())
453     }
454 
455     fn resize(
456         &self,
457         _tty: Arc<TtyCore>,
458         _winsize: super::termios::WindowSize,
459     ) -> Result<(), SystemError> {
460         todo!()
461     }
462 }
463 
464 #[derive(Debug, Clone)]
465 pub struct VtModeData {
466     mode: VtMode,
467     /// 释放请求时触发的信号
468     relsig: u16,
469     /// 获取请求时触发的信号
470     acqsig: u16,
471 }
472 
473 #[allow(dead_code)]
474 #[derive(Debug, Clone)]
475 pub enum VtMode {
476     /// 自动切换模式,即在请求输入时自动切换到终端
477     Auto,
478     /// 手动切换模式,需要通过 ioctl 请求切换到终端
479     Process,
480     /// 等待终端确认,即在切换到终端时等待终端的确认信号
481     Ackacq,
482 }
483 
484 /// 用于给vc确定要写入的buf位置
485 #[derive(Debug, Default)]
486 pub struct DrawRegion {
487     /// 偏移量
488     pub offset: usize,
489     /// 写入数量
490     pub size: usize,
491     pub x: Option<u32>,
492 }
493 
494 // 初始化虚拟终端
495 #[inline(never)]
496 pub fn vty_init() -> Result<(), SystemError> {
497     if let Ok(tty_console_driver_inner) = TtyConsoleDriverInner::new() {
498         let console_driver = TtyDriver::new(
499             MAX_NR_CONSOLES,
500             "tty",
501             0,
502             Major::TTY_MAJOR,
503             0,
504             TtyDriverType::Console,
505             *TTY_STD_TERMIOS,
506             Arc::new(tty_console_driver_inner),
507             None,
508         );
509 
510         TtyDriverManager::tty_register_driver(console_driver).inspect(|_| {
511             log::error!("tty console: register driver failed");
512         })?;
513     }
514 
515     Ok(())
516 }
517 
518 #[unified_init(INITCALL_LATE)]
519 fn vty_late_init() -> Result<(), SystemError> {
520     let (_, console_driver) =
521         TtyDriverManager::lookup_tty_driver(DeviceNumber::new(Major::TTY_MAJOR, 0))
522             .ok_or(SystemError::ENODEV)?;
523     console_driver.init_tty_device(None)?;
524 
525     vc_manager().setup_default_vc();
526     Ok(())
527 }
528