1 use core::{ 2 fmt::Debug, 3 intrinsics::unlikely, 4 sync::atomic::{AtomicBool, AtomicU32, Ordering}, 5 }; 6 7 use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc}; 8 use system_error::SystemError; 9 10 use crate::{ 11 driver::{ 12 serial::serial8250::send_to_default_serial8250_port, 13 video::{has_video_refresh_manager, video_refresh_manager}, 14 }, 15 libs::{lib_ui::textui::textui_is_enable_put_to_window, rwlock::RwLock, spinlock::SpinLock}, 16 mm::{mmio_buddy::MMIOSpaceGuard, VirtAddr}, 17 }; 18 19 use super::{ 20 textui::{textui_disable_put_to_window, textui_enable_put_to_window}, 21 textui_no_alloc::textui_init_no_alloc, 22 }; 23 24 /// 全局的UI框架列表 25 pub static SCM_FRAMEWORK_LIST: SpinLock<LinkedList<Arc<dyn ScmUiFramework>>> = 26 SpinLock::new(LinkedList::new()); 27 28 /// 当前在使用的UI框架 29 pub static CURRENT_FRAMEWORK: RwLock<Option<Arc<dyn ScmUiFramework>>> = RwLock::new(None); 30 31 /// 是否启用双缓冲 32 pub static SCM_DOUBLE_BUFFER_ENABLED: AtomicBool = AtomicBool::new(false); 33 34 bitflags! { 35 pub struct ScmBufferFlag:u8 { 36 // 帧缓冲区标志位 37 const SCM_BF_FB = 1 << 0; // 当前buffer是设备显存中的帧缓冲区 38 const SCM_BF_DB = 1 << 1; // 当前buffer是双缓冲 39 const SCM_BF_TEXT = 1 << 2; // 使用文本模式 40 const SCM_BF_PIXEL = 1 << 3; // 使用图像模式 41 } 42 } 43 #[derive(Clone, Debug)] 44 #[allow(dead_code)] 45 pub enum ScmFramworkType { 46 Text, 47 Gui, 48 Unused, 49 } 50 #[derive(Debug, Clone)] 51 pub enum ScmBuffer { 52 DeviceBuffer(VirtAddr), 53 DoubleBuffer(Arc<SpinLock<Box<[u8]>>>), 54 } 55 56 #[derive(Debug, Clone)] 57 pub struct ScmBufferInfo { 58 width: u32, // 帧缓冲区宽度(pixel或columns) 59 height: u32, // 帧缓冲区高度(pixel或lines) 60 size: u32, // 帧缓冲区大小(bytes) 61 bit_depth: u32, // 像素点位深度 62 device_buffer_mmio_guard: Option<Arc<MMIOSpaceGuard>>, 63 pub buf: ScmBuffer, 64 flags: ScmBufferFlag, // 帧缓冲区标志位 65 } 66 67 #[allow(dead_code)] 68 impl ScmBufferInfo { 69 /// 创建新的帧缓冲区信息 70 /// 71 /// ## 参数 72 /// 73 /// - `buf_type` 帧缓冲区类型 74 /// 75 /// ## 返回值 76 /// 77 /// - `Result<Self, SystemError>` 创建成功返回新的帧缓冲区结构体,创建失败返回错误码 78 pub fn new(mut buf_type: ScmBufferFlag) -> Result<Self, SystemError> { 79 if unlikely(!SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst)) { 80 let mut device_buffer = video_refresh_manager().device_buffer().clone(); 81 buf_type.remove(ScmBufferFlag::SCM_BF_DB); 82 buf_type.insert(ScmBufferFlag::SCM_BF_FB); 83 device_buffer.flags = buf_type; 84 return Ok(device_buffer); 85 } else { 86 let device_buffer_guard = video_refresh_manager().device_buffer(); 87 88 let buf_space: Arc<SpinLock<Box<[u8]>>> = Arc::new(SpinLock::new( 89 vec![0u8; (device_buffer_guard.size / 4) as usize].into_boxed_slice(), 90 )); 91 92 assert!(buf_type.contains(ScmBufferFlag::SCM_BF_DB)); 93 94 assert_eq!( 95 device_buffer_guard.size as usize, 96 buf_space.lock().len() * core::mem::size_of::<u8>() 97 ); 98 99 // 创建双缓冲区 100 let buffer = Self { 101 width: device_buffer_guard.width, 102 height: device_buffer_guard.height, 103 size: device_buffer_guard.size, 104 bit_depth: device_buffer_guard.bit_depth, 105 flags: buf_type, 106 buf: ScmBuffer::DoubleBuffer(buf_space), 107 device_buffer_mmio_guard: None, 108 }; 109 drop(device_buffer_guard); 110 111 return Ok(buffer); 112 } 113 } 114 115 pub unsafe fn set_device_buffer_mmio_guard(&mut self, guard: Arc<MMIOSpaceGuard>) { 116 self.device_buffer_mmio_guard = Some(guard); 117 } 118 119 pub unsafe fn new_device_buffer( 120 width: u32, 121 height: u32, 122 size: u32, 123 bit_depth: u32, 124 buf_type: ScmBufferFlag, 125 vaddr: VirtAddr, 126 mut device_buffer_mmio_guard: Option<MMIOSpaceGuard>, 127 ) -> Result<Self, SystemError> { 128 let mmio_guard = device_buffer_mmio_guard.take().map(Arc::new); 129 let buffer = Self { 130 width, 131 height, 132 size, 133 bit_depth, 134 flags: buf_type, 135 buf: ScmBuffer::DeviceBuffer(vaddr), 136 device_buffer_mmio_guard: mmio_guard, 137 }; 138 return Ok(buffer); 139 } 140 141 pub fn buf_size(&self) -> usize { 142 self.size as usize 143 } 144 145 pub fn bit_depth(&self) -> u32 { 146 self.bit_depth 147 } 148 149 pub fn height(&self) -> u32 { 150 self.height 151 } 152 153 pub fn width(&self) -> u32 { 154 self.width 155 } 156 157 pub fn is_double_buffer(&self) -> bool { 158 matches!(&self.buf, ScmBuffer::DoubleBuffer(_)) 159 } 160 pub fn is_device_buffer(&self) -> bool { 161 matches!(&self.buf, ScmBuffer::DeviceBuffer(_)) 162 } 163 164 pub fn copy_from_nonoverlapping(&mut self, src: &ScmBufferInfo) { 165 assert!(self.buf_size() == src.buf_size()); 166 match &self.buf { 167 ScmBuffer::DeviceBuffer(vaddr) => { 168 let len = self.buf_size() / core::mem::size_of::<u32>(); 169 let self_buf_guard = 170 unsafe { core::slice::from_raw_parts_mut(vaddr.data() as *mut u8, len) }; 171 match &src.buf { 172 ScmBuffer::DeviceBuffer(vaddr) => { 173 let src_buf_guard = 174 unsafe { core::slice::from_raw_parts(vaddr.data() as *const u8, len) }; 175 self_buf_guard.copy_from_slice(src_buf_guard); 176 } 177 ScmBuffer::DoubleBuffer(double_buffer) => { 178 let src_buf_guard = double_buffer.lock(); 179 self_buf_guard.copy_from_slice(src_buf_guard.as_ref()); 180 } 181 }; 182 } 183 184 ScmBuffer::DoubleBuffer(double_buffer) => { 185 let mut double_buffer_guard = double_buffer.lock(); 186 match &src.buf { 187 ScmBuffer::DeviceBuffer(vaddr) => { 188 let len = src.buf_size() / core::mem::size_of::<u8>(); 189 double_buffer_guard.as_mut().copy_from_slice(unsafe { 190 core::slice::from_raw_parts(vaddr.data() as *const u8, len) 191 }); 192 } 193 ScmBuffer::DoubleBuffer(double_buffer) => { 194 let x = double_buffer.lock(); 195 double_buffer_guard.as_mut().copy_from_slice(x.as_ref()); 196 } 197 }; 198 } 199 } 200 } 201 } 202 203 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] 204 pub struct ScmUiFrameworkId(u32); 205 206 impl ScmUiFrameworkId { 207 /// 分配一个新的框架id 208 pub fn new() -> Self { 209 static MAX_ID: AtomicU32 = AtomicU32::new(0); 210 return ScmUiFrameworkId(MAX_ID.fetch_add(1, Ordering::SeqCst)); 211 } 212 } 213 #[allow(dead_code)] 214 #[derive(Debug, Clone)] 215 pub struct ScmUiFrameworkMetadata { 216 id: ScmUiFrameworkId, 217 name: String, 218 framework_type: ScmFramworkType, 219 pub buf_info: ScmBufferInfo, 220 } 221 222 impl ScmUiFrameworkMetadata { 223 pub fn new(name: String, framework_type: ScmFramworkType) -> Self { 224 match framework_type { 225 ScmFramworkType::Text => { 226 let result = ScmUiFrameworkMetadata { 227 id: ScmUiFrameworkId::new(), 228 name, 229 framework_type: ScmFramworkType::Text, 230 buf_info: ScmBufferInfo::new( 231 ScmBufferFlag::SCM_BF_TEXT | ScmBufferFlag::SCM_BF_DB, 232 ) 233 .unwrap(), 234 }; 235 236 return result; 237 } 238 ScmFramworkType::Gui => todo!(), 239 ScmFramworkType::Unused => todo!(), 240 } 241 } 242 pub fn buf_info(&self) -> ScmBufferInfo { 243 return self.buf_info.clone(); 244 } 245 pub fn set_buf_info(&mut self, buf_info: ScmBufferInfo) { 246 self.buf_info = buf_info; 247 } 248 } 249 pub trait ScmUiFramework: Sync + Send + Debug { 250 // 安装ui框架的回调函数 251 fn install(&self) -> Result<i32, SystemError> { 252 return Err(SystemError::ENOSYS); 253 } 254 // 卸载ui框架的回调函数 255 #[allow(dead_code)] 256 fn uninstall(&self) -> Result<i32, SystemError> { 257 return Err(SystemError::ENOSYS); 258 } 259 // 启用ui框架的回调函数 260 fn enable(&self) -> Result<i32, SystemError> { 261 return Err(SystemError::ENOSYS); 262 } 263 // 禁用ui框架的回调函数 264 fn disable(&self) -> Result<i32, SystemError> { 265 return Err(SystemError::ENOSYS); 266 } 267 // 改变ui框架的帧缓冲区的回调函数 268 fn change(&self, _buf: ScmBufferInfo) -> Result<i32, SystemError> { 269 return Err(SystemError::ENOSYS); 270 } 271 /// @brief 获取ScmUiFramework的元数据 272 /// @return 成功:Ok(ScmUiFramework的元数据) 273 /// 失败:Err(错误码) 274 fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> { 275 // 若文件系统没有实现此方法,则返回“不支持” 276 return Err(SystemError::ENOSYS); 277 } 278 } 279 280 /// 初始化屏幕控制模块 281 /// 282 /// ## 调用时机 283 /// 284 /// 该函数在内核启动的早期进行调用。调用时,内存管理模块尚未初始化。 285 pub fn scm_init(enable_put_to_window: bool) { 286 SCM_DOUBLE_BUFFER_ENABLED.store(false, Ordering::SeqCst); // 禁用双缓冲 287 if enable_put_to_window { 288 textui_enable_put_to_window(); 289 } else { 290 textui_disable_put_to_window(); 291 } 292 textui_init_no_alloc(enable_put_to_window); 293 294 send_to_default_serial8250_port("\nfinish_scm_init\n\0".as_bytes()); 295 } 296 297 /// 启用某个ui框架,将它的帧缓冲区渲染到屏幕上 298 /// ## 参数 299 /// 300 /// - framework 要启动的ui框架 301 302 pub fn scm_framework_enable(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> { 303 // 获取信息 304 let metadata = framework.metadata()?; 305 306 // if metadata.buf_info.buf.is_null() { 307 // return Err(SystemError::EINVAL); 308 // } 309 let mut current_framework = CURRENT_FRAMEWORK.write(); 310 311 if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) { 312 video_refresh_manager().set_refresh_target(&metadata.buf_info)?; 313 } 314 315 framework.enable()?; 316 current_framework.replace(framework); 317 318 return Ok(0); 319 } 320 /// 向屏幕管理器注册UI框架 321 /// 322 /// ## 参数 323 /// - framework 框架结构体 324 325 pub fn scm_register(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> { 326 // 把ui框架加入链表 327 328 SCM_FRAMEWORK_LIST.lock().push_back(framework.clone()); 329 // 调用ui框架的回调函数以安装ui框架,并将其激活 330 framework.install()?; 331 332 // 如果当前还没有框架获得了屏幕的控制权,就让其拿去 333 if CURRENT_FRAMEWORK.read().is_none() { 334 return scm_framework_enable(framework); 335 } 336 return Ok(0); 337 } 338 339 /// 屏幕管理器启用双缓冲区 340 #[allow(dead_code)] 341 pub fn scm_enable_double_buffer() -> Result<i32, SystemError> { 342 if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) { 343 // 已经开启了双缓冲区了, 直接退出 344 return Ok(0); 345 } 346 let scm_list = SCM_FRAMEWORK_LIST.lock(); 347 if scm_list.is_empty() { 348 // scm 框架链表为空 349 return Ok(0); 350 } 351 drop(scm_list); 352 SCM_DOUBLE_BUFFER_ENABLED.store(true, Ordering::SeqCst); 353 // 创建双缓冲区 354 let buf_info = ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?; 355 356 // 设置定时刷新的对象 357 video_refresh_manager() 358 .set_refresh_target(&buf_info) 359 .expect("set refresh target failed"); 360 361 // 设置当前框架的帧缓冲区 362 CURRENT_FRAMEWORK 363 .write() 364 .as_ref() 365 .unwrap() 366 .change(buf_info)?; 367 // 遍历当前所有使用帧缓冲区的框架,更新为双缓冲区 368 for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() { 369 if !(*framework).metadata()?.buf_info.is_double_buffer() { 370 let new_buf_info = 371 ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?; 372 (*framework).change(new_buf_info)?; 373 } 374 } 375 // 通知显示驱动,启动双缓冲 376 video_refresh_manager().video_reinitialize(true)?; 377 378 return Ok(0); 379 } 380 381 /// 允许往窗口打印信息 382 pub fn scm_enable_put_to_window() { 383 // mm之前要继续往窗口打印信息时,因为没有动态内存分配(textui并没有往scm注册),且使用的是textui,要直接修改textui里面的值 384 if CURRENT_FRAMEWORK.read().is_none() { 385 textui_enable_put_to_window(); 386 } else { 387 let r = CURRENT_FRAMEWORK 388 .write() 389 .as_ref() 390 .unwrap() 391 .enable() 392 .unwrap_or_else(|e| e.to_posix_errno()); 393 if r.is_negative() { 394 send_to_default_serial8250_port("scm_enable_put_to_window() failed.\n\0".as_bytes()); 395 } 396 } 397 } 398 /// 禁止往窗口打印信息 399 pub fn scm_disable_put_to_window() { 400 // mm之前要停止往窗口打印信息时,因为没有动态内存分配(rwlock与otion依然能用,但是textui并没有往scm注册),且使用的是textui,要直接修改textui里面的值 401 if CURRENT_FRAMEWORK.read().is_none() { 402 textui_disable_put_to_window(); 403 assert!(!textui_is_enable_put_to_window()); 404 } else { 405 let r = CURRENT_FRAMEWORK 406 .write() 407 .as_ref() 408 .unwrap() 409 .disable() 410 .unwrap_or_else(|e| e.to_posix_errno()); 411 if r.is_negative() { 412 send_to_default_serial8250_port("scm_disable_put_to_window() failed.\n\0".as_bytes()); 413 } 414 } 415 } 416 /// 当内存管理单元被初始化之后,重新处理帧缓冲区问题 417 #[inline(never)] 418 pub fn scm_reinit() -> Result<(), SystemError> { 419 #[cfg(target_arch = "x86_64")] 420 { 421 let r = true_scm_reinit(); 422 if r.is_err() { 423 send_to_default_serial8250_port("scm reinit failed.\n\0".as_bytes()); 424 } 425 return r; 426 } 427 428 #[cfg(not(target_arch = "x86_64"))] 429 { 430 return Ok(()); 431 } 432 } 433 434 #[allow(dead_code)] 435 fn true_scm_reinit() -> Result<(), SystemError> { 436 if !has_video_refresh_manager() { 437 return Err(SystemError::ENODEV); 438 } 439 video_refresh_manager().video_reinitialize(false)?; 440 441 // 遍历当前所有使用帧缓冲区的框架,更新地址 442 let device_buffer = video_refresh_manager().device_buffer().clone(); 443 for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() { 444 if framework.metadata()?.buf_info().is_device_buffer() { 445 framework.change(device_buffer.clone())?; 446 } 447 } 448 449 scm_enable_put_to_window(); 450 451 return Ok(()); 452 } 453