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]
vc_manager() -> &'static VirtConsoleManager63 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 {
new(vc_data: Option<Arc<SpinLock<VirtualConsoleData>>>) -> Arc<Self>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
vc_data(&self) -> Option<Arc<SpinLock<VirtualConsoleData>>>88 pub fn vc_data(&self) -> Option<Arc<SpinLock<VirtualConsoleData>>> {
89 self.vc_data.clone()
90 }
91
port(&self) -> Arc<dyn TtyPort>92 pub fn port(&self) -> Arc<dyn TtyPort> {
93 self.port.clone()
94 }
95
index(&self) -> Option<usize>96 pub fn index(&self) -> Option<usize> {
97 self.index.try_get().cloned()
98 }
99
devfs_setup(&self) -> Result<(), SystemError>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
devfs_remove(&self)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
new() -> Self150 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
get(&self, index: usize) -> Option<Arc<VirtConsole>>160 pub fn get(&self, index: usize) -> Option<Arc<VirtConsole>> {
161 let inner = self.inner.lock();
162 inner.consoles.get(&index).cloned()
163 }
164
alloc(&self, vc: Arc<VirtConsole>) -> Option<usize>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 /// 释放虚拟终端
free(&self, index: usize)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 /// 获取当前虚拟终端
current_vc(&self) -> Option<Arc<VirtConsole>>187 pub fn current_vc(&self) -> Option<Arc<VirtConsole>> {
188 self.current_vc.read().as_ref().map(|(vc, _)| vc.clone())
189 }
190
current_vc_index(&self) -> Option<usize>191 pub fn current_vc_index(&self) -> Option<usize> {
192 self.current_vc.read().as_ref().map(|(_, index)| *index)
193 }
194
current_vc_tty_name(&self) -> Option<String>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 /// 设置当前虚拟终端
set_current_vc(&self, vc: Arc<VirtConsole>)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)
lookup_vc_by_tty_name(&self, name: &str) -> Option<Arc<VirtConsole>>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
setup_default_vc(&self)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 {
from_256(col: u32) -> Self253 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 {
fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result283 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
284 write!(f, "TtyConsoleDriverInner")
285 }
286 }
287
288 impl TtyConsoleDriverInner {
new() -> Result<Self, SystemError>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
do_install(&self, tty: Arc<TtyCore>, vc: &Arc<VirtConsole>) -> Result<(), SystemError>303 fn do_install(&self, tty: Arc<TtyCore>, vc: &Arc<VirtConsole>) -> Result<(), SystemError> {
304 let tty_core = tty.core();
305
306 let binding = vc.vc_data().unwrap();
307 let mut vc_data = binding.lock();
308
309 self.console.con_init(vc, &mut vc_data, true)?;
310 if vc_data.complement_mask == 0 {
311 vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 };
312 }
313 vc_data.s_complement_mask = vc_data.complement_mask;
314 // vc_data.bytes_per_row = vc_data.cols << 1;
315 vc_data.index = tty_core.index();
316 vc_data.bottom = vc_data.rows;
317 vc_data.set_driver_funcs(Arc::downgrade(
318 &(self.console.clone() as Arc<dyn ConsoleSwitch>),
319 ));
320
321 // todo: unicode字符集处理?
322
323 if vc_data.cols > VC_MAXCOL || vc_data.rows > VC_MAXROW {
324 return Err(SystemError::EINVAL);
325 }
326
327 vc_data.init(None, None, true);
328 vc_data.update_attr();
329
330 let window_size = tty_core.window_size_upgradeable();
331 if window_size.col == 0 && window_size.row == 0 {
332 let mut window_size = window_size.upgrade();
333 window_size.col = vc_data.cols as u16;
334 window_size.row = vc_data.rows as u16;
335 }
336
337 if vc_data.utf {
338 tty_core.termios_write().input_mode.insert(InputMode::IUTF8);
339 } else {
340 tty_core.termios_write().input_mode.remove(InputMode::IUTF8);
341 }
342
343 // 设置tty的端口为vc端口
344 vc.port().setup_internal_tty(Arc::downgrade(&tty));
345 tty.set_port(vc.port());
346 vc.devfs_setup()?;
347 // 加入sysfs?
348
349 Ok(())
350 }
351 }
352
353 impl TtyOperation for TtyConsoleDriverInner {
install(&self, _driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError>354 fn install(&self, _driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> {
355 let vc = VirtConsole::new(Some(Arc::new(SpinLock::new(VirtualConsoleData::new(
356 usize::MAX,
357 )))));
358 vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?;
359 self.do_install(tty, &vc)
360 .inspect_err(|_| vc_manager().free(vc.index().unwrap()))?;
361
362 Ok(())
363 }
364
open(&self, _tty: &TtyCoreData) -> Result<(), SystemError>365 fn open(&self, _tty: &TtyCoreData) -> Result<(), SystemError> {
366 Ok(())
367 }
368
write_room(&self, _tty: &TtyCoreData) -> usize369 fn write_room(&self, _tty: &TtyCoreData) -> usize {
370 32768
371 }
372
373 /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/vt/vt.c#2894
374 #[inline(never)]
write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError>375 fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError> {
376 // if String::from_utf8_lossy(buf) == "Hello world!\n" {
377 // loop {}
378 // }
379 send_to_default_serial8250_port(buf);
380 let ret = tty.do_write(buf, nr);
381 self.flush_chars(tty);
382 ret
383 }
384
385 #[inline(never)]
flush_chars(&self, tty: &TtyCoreData)386 fn flush_chars(&self, tty: &TtyCoreData) {
387 let vc_data = tty.vc_data().unwrap();
388 let mut vc_data_guard = vc_data.lock_irqsave();
389 vc_data_guard.set_cursor();
390 }
391
put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError>392 fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> {
393 self.write(tty, &[ch], 1)?;
394 Ok(())
395 }
396
ioctl(&self, _tty: Arc<TtyCore>, _cmd: u32, _arg: usize) -> Result<(), SystemError>397 fn ioctl(&self, _tty: Arc<TtyCore>, _cmd: u32, _arg: usize) -> Result<(), SystemError> {
398 // TODO
399 Err(SystemError::ENOIOCTLCMD)
400 }
401
close(&self, _tty: Arc<TtyCore>) -> Result<(), SystemError>402 fn close(&self, _tty: Arc<TtyCore>) -> Result<(), SystemError> {
403 Ok(())
404 }
405
resize( &self, _tty: Arc<TtyCore>, _winsize: super::termios::WindowSize, ) -> Result<(), SystemError>406 fn resize(
407 &self,
408 _tty: Arc<TtyCore>,
409 _winsize: super::termios::WindowSize,
410 ) -> Result<(), SystemError> {
411 todo!()
412 }
413 }
414
415 #[derive(Debug, Clone)]
416 pub struct VtModeData {
417 mode: VtMode,
418 /// 释放请求时触发的信号
419 relsig: u16,
420 /// 获取请求时触发的信号
421 acqsig: u16,
422 }
423
424 #[allow(dead_code)]
425 #[derive(Debug, Clone)]
426 pub enum VtMode {
427 /// 自动切换模式,即在请求输入时自动切换到终端
428 Auto,
429 /// 手动切换模式,需要通过 ioctl 请求切换到终端
430 Process,
431 /// 等待终端确认,即在切换到终端时等待终端的确认信号
432 Ackacq,
433 }
434
435 /// 用于给vc确定要写入的buf位置
436 #[derive(Debug, Default)]
437 pub struct DrawRegion {
438 /// 偏移量
439 pub offset: usize,
440 /// 写入数量
441 pub size: usize,
442 pub x: Option<u32>,
443 }
444
445 // 初始化虚拟终端
446 #[inline(never)]
vty_init() -> Result<(), SystemError>447 pub fn vty_init() -> Result<(), SystemError> {
448 if let Ok(tty_console_driver_inner) = TtyConsoleDriverInner::new() {
449 const NAME: &str = "tty";
450 let console_driver = TtyDriver::new(
451 MAX_NR_CONSOLES,
452 NAME,
453 0,
454 Major::TTY_MAJOR,
455 0,
456 TtyDriverType::Console,
457 *TTY_STD_TERMIOS,
458 Arc::new(tty_console_driver_inner),
459 None,
460 );
461
462 TtyDriverManager::tty_register_driver(console_driver).inspect_err(|e| {
463 log::error!("tty console: register driver {} failed: {:?}", NAME, e);
464 })?;
465 }
466
467 Ok(())
468 }
469
470 #[unified_init(INITCALL_LATE)]
vty_late_init() -> Result<(), SystemError>471 fn vty_late_init() -> Result<(), SystemError> {
472 let (_, console_driver) =
473 TtyDriverManager::lookup_tty_driver(DeviceNumber::new(Major::TTY_MAJOR, 0))
474 .ok_or(SystemError::ENODEV)?;
475 console_driver.init_tty_device(None).ok();
476
477 vc_manager().setup_default_vc();
478 Ok(())
479 }
480