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_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 { 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 365 fn open(&self, _tty: &TtyCoreData) -> Result<(), SystemError> { 366 Ok(()) 367 } 368 369 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)] 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)] 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 392 fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> { 393 self.write(tty, &[ch], 1)?; 394 Ok(()) 395 } 396 397 fn ioctl(&self, _tty: Arc<TtyCore>, _cmd: u32, _arg: usize) -> Result<(), SystemError> { 398 // TODO 399 Err(SystemError::ENOIOCTLCMD) 400 } 401 402 fn close(&self, _tty: Arc<TtyCore>) -> Result<(), SystemError> { 403 Ok(()) 404 } 405 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)] 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)] 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