Browse Source

Patch refactor scm and textui (#289)

* 重构屏幕管理器和textui框架

* 切换字体为spleen,并增加对字体的抽象

* 修正文档

---------

Co-authored-by: longjin <[email protected]>
hanjiezhou 1 year ago
parent
commit
abe3a6ea3c
42 changed files with 2006 additions and 1727 deletions
  1. 0 1
      .vscode/settings.json
  2. 1 0
      docs/index.rst
  3. 12 0
      docs/kernel/libs/index.rst
  4. 83 0
      docs/kernel/libs/lib_ui/scm.md
  5. 32 0
      docs/kernel/libs/lib_ui/textui.md
  6. 4 17
      kernel/src/arch/x86_64/mm/mod.rs
  7. 2 2
      kernel/src/common/atomic.h
  8. 0 316
      kernel/src/common/font.h
  9. 10 14
      kernel/src/common/printk.h
  10. 1 1
      kernel/src/driver/interrupt/apic/apic.c
  11. 7 6
      kernel/src/driver/tty/tty_device.rs
  12. 30 13
      kernel/src/driver/video/video.c
  13. 9 7
      kernel/src/driver/video/video.h
  14. 10 2
      kernel/src/head.S
  15. 1 1
      kernel/src/include/bindings/wrapper.h
  16. 4 4
      kernel/src/lib.rs
  17. 1 1
      kernel/src/libs/Makefile
  18. 0 13
      kernel/src/libs/libUI/Makefile
  19. 0 351
      kernel/src/libs/libUI/screen_manager.c
  20. 0 120
      kernel/src/libs/libUI/screen_manager.h
  21. 0 154
      kernel/src/libs/libUI/textui-render.c
  22. 0 372
      kernel/src/libs/libUI/textui.c
  23. 0 187
      kernel/src/libs/libUI/textui.h
  24. BIN
      kernel/src/libs/lib_ui/font/binaries/spleen-8x16.raw_bytes
  25. 90 0
      kernel/src/libs/lib_ui/font/mod.rs
  26. 25 0
      kernel/src/libs/lib_ui/font/spleen_font.rs
  27. 4 0
      kernel/src/libs/lib_ui/mod.rs
  28. 58 0
      kernel/src/libs/lib_ui/screen_manager.h
  29. 475 0
      kernel/src/libs/lib_ui/screen_manager.rs
  30. 19 0
      kernel/src/libs/lib_ui/textui.h
  31. 967 0
      kernel/src/libs/lib_ui/textui.rs
  32. 125 0
      kernel/src/libs/lib_ui/textui_no_alloc.rs
  33. 1 0
      kernel/src/libs/mod.rs
  34. 2 2
      kernel/src/libs/printk.c
  35. 13 134
      kernel/src/libs/printk.rs
  36. 1 0
      kernel/src/libs/spinlock.rs
  37. 9 6
      kernel/src/main.c
  38. 2 1
      kernel/src/mm/no_init.rs
  39. 0 1
      tools/.gdbinit
  40. 3 1
      user/apps/shell/cmd.c
  41. 4 0
      user/apps/shell/shell.c
  42. 1 0
      user/libs/libc/src/unistd.c

+ 0 - 1
.vscode/settings.json

@@ -4,7 +4,6 @@
         "stdbool.h": "c",
         "printk.h": "c",
         "stdarg.h": "c",
-        "font.h": "c",
         "trap.h": "c",
         "gate.h": "c",
         "process.h": "c",

+ 1 - 0
docs/index.rst

@@ -29,6 +29,7 @@
    kernel/debug/index
    kernel/ktest/index
    kernel/cpu_arch/index
+   kernel/libs/index
 
 
 .. toctree::

+ 12 - 0
docs/kernel/libs/index.rst

@@ -0,0 +1,12 @@
+====================================
+其他内核库
+====================================
+
+   这里的集中了内核中的一些库的文档,这些库不属于任何子系统。
+   
+.. toctree::
+   :maxdepth: 1
+
+   lib_ui/scm
+   lib_ui/textui
+

+ 83 - 0
docs/kernel/libs/lib_ui/scm.md

@@ -0,0 +1,83 @@
+# 屏幕管理器(SCM)
+
+:::{note}
+作者: 周瀚杰 <[email protected]>
+:::
+&emsp;&emsp;屏幕管理器用来管理控制所有ui框架,所有框架都必须先在屏幕管理器中注册才可使用,然后scm控制当前是哪个ui框架在使用
+
+## traits
+
+### ScmUiFramework
+&emsp;&emsp;每个要注册到scm中的ui框架都必须实现这个trait中的方法,具体定义如下:
+```rust
+pub trait ScmUiFramework: Sync + Send + Debug {
+    // 安装ui框架的回调函数
+    fn install(&self) -> Result<i32, SystemError> {
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+    // 卸载ui框架的回调函数
+    fn uninstall(&self) -> Result<i32, SystemError> {
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+    // 启用ui框架的回调函数
+    fn enable(&self) -> Result<i32, SystemError> {
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+    // 禁用ui框架的回调函数
+    fn disable(&self) -> Result<i32, SystemError> {
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+    // 改变ui框架的帧缓冲区的回调函数
+    fn change(&self, _buf: ScmBufferInfo) -> Result<i32, SystemError> {
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+    /// @brief 获取ScmUiFramework的元数据
+    /// @return 成功:Ok(ScmUiFramework的元数据)
+    ///         失败:Err(错误码)
+    fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
+        // 若文件系统没有实现此方法,则返回“不支持”
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+}
+```
+## 主要API
+### scm_init() -初始化屏幕管理模块
+#### 原型
+```rust
+pub extern "C" fn scm_init()
+```
+#### 说明
+&emsp;&emsp;scm_init()主要是初始化一些scm中使用的全局变量,例如是否使用双缓冲区标志位,textui未初始化时使用的一些全局变量
+
+### scm_reinit() -当内存管理单元被初始化之后,重新初始化屏幕管理模块
+#### 原型
+```rust
+pub extern "C" fn scm_reinit() -> i32
+```
+#### 说明
+&emsp;&emsp;scm_reinit()用于当内存管理单元被初始化之后,重新处理帧缓冲区问题
+
+### scm_enable_double_buffer() -允许双缓冲区
+#### 原型
+```rust
+pub extern "C" fn scm_enable_double_buffer() -> i32
+```
+#### 说明
+&emsp;&emsp;scm_enable_double_buffer()用于启动双缓冲来往窗口输出打印信息。启用后,往窗口输出的信息会暂时放在一个缓冲区中,然后每次按一定时间将该缓冲区的信息输出到窗口帧缓冲区中,渲染显示到窗口上。
+
+### scm_framework_enable() -启用某个ui框架,将它的帧缓冲区渲染到屏幕上
+#### 原型
+```rust
+pub fn scm_framework_enable(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError>
+```
+#### 说明
+&emsp;&emsp;scm_framework_enable用于启用某个ui框架,将它的帧缓冲区渲染到屏幕上
+
+
+### scm_register() -向屏幕管理器注册UI框架
+#### 原型
+```rust
+pub fn scm_register(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> 
+```
+#### 说明
+&emsp;&emsp;scm_register用于将ui框架注册到scm中,主要是调用ui框架的回调函数以安装ui框架,并将其激活

+ 32 - 0
docs/kernel/libs/lib_ui/textui.md

@@ -0,0 +1,32 @@
+# 文本显示框架(textui)
+
+:::{note}
+作者: 周瀚杰 <[email protected]>
+:::
+&emsp;&emsp;文本框架主要用于DragonOS的文本的窗口渲染显示,往屏幕窗口中输出打印文本信息,往窗口显示文本分成两种情况:一种是当内存管理单元(mm)未被初始化时,不能进行动态内存分配,限制颇多(例如不能使用vec,mpsc等),所以直接往窗口的帧缓冲区输出打印信息,不使用虚拟行等复杂结构体;另一种是当内存管理单元(mm)已经初始化,可以进行动态内存分配,便可以使用一些复杂的结构体来处理要打印的文本信息。
+
+
+## 主要API
+### rs_textui_init() -textui框架初始化
+#### 原型
+```rust
+pub extern "C" fn rs_textui_init() -> i32
+```
+#### 说明
+&emsp;&emsp;rs_textui_init()主要是初始化一些textui框架要使用到的一些全局变量信息(例如TEXTUIFRAMEWORK,TEXTUI_PRIVATE_INFO等),以及将textui框架注册到scm中。
+
+### textui_putchar() -往textui框架中的当前使用的窗口打印文本信息
+#### 原型
+```rust
+pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32
+
+pub fn textui_putchar(
+    character: char,
+    fr_color: FontColor,
+    bk_color: FontColor,
+) -> Result<(), SystemError> 
+```
+#### 说明
+&emsp;&emsp;textui_putchar()要处理两种情况:一种是当内存管理单元(mm)未被初始化时,不能进行动态内存分配,限制颇多(例如不能使用vec,mpsc等),所以直接往窗口的帧缓冲区输出打印信息,不使用虚拟行等复杂结构体;另一种是当内存管理单元(mm)已经初始化,可以进行动态内存分配,便可以使用一些复杂的结构体来处理要打印的文本信息。
+
+

+ 4 - 17
kernel/src/arch/x86_64/mm/mod.rs

@@ -7,10 +7,10 @@ use x86_64::registers::model_specific::EferFlags;
 
 use crate::driver::uart::uart::c_uart_send_str;
 use crate::include::bindings::bindings::{
-    disable_textui, enable_textui, multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
-    video_reinitialize,
+    multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
 };
 use crate::libs::align::page_align_up;
+use crate::libs::lib_ui::screen_manager::scm_disable_put_to_window;
 use crate::libs::printk::PrintkWriter;
 use crate::libs::spinlock::SpinLock;
 
@@ -315,8 +315,6 @@ pub fn mm_init() {
     unsafe { allocator_init() };
     // enable mmio
     mmio_init();
-    // 启用printk的alloc选项
-    PrintkWriter.enable_alloc();
 }
 
 unsafe fn allocator_init() {
@@ -396,9 +394,8 @@ unsafe fn allocator_init() {
     unsafe { set_inner_allocator(buddy_allocator) };
     kinfo!("Successfully initialized buddy allocator");
     // 关闭显示输出
-    unsafe {
-        disable_textui();
-    }
+    scm_disable_put_to_window();
+
     // make the new page table current
     {
         let mut binding = INNER_ALLOCATOR.lock();
@@ -416,16 +413,6 @@ unsafe fn allocator_init() {
         kdebug!("New page table enabled");
     }
     kdebug!("Successfully enabled new page table");
-    // 重置显示输出目标
-    unsafe {
-        video_reinitialize(false);
-    }
-
-    // 打开显示输出
-    unsafe {
-        enable_textui();
-    }
-    kdebug!("Text UI enabled");
 }
 
 #[no_mangle]

+ 2 - 2
kernel/src/common/atomic.h

@@ -11,8 +11,8 @@
 #pragma once
 #include <arch/x86_64/include/asm/cmpxchg.h>
 
-#define atomic_read(atomic)	((atomic)->value)   // 读取原子变量
-#define atomic_set(atomic,val)	(((atomic)->value) = (val)) // 设置原子变量的初始值
+#define atomic_read(atomic) ((atomic)->value)               // 读取原子变量
+#define atomic_set(atomic, val) (((atomic)->value) = (val)) // 设置原子变量的初始值
 
 typedef struct
 {

+ 0 - 316
kernel/src/common/font.h

@@ -1,316 +0,0 @@
-#pragma once
-
-unsigned char font_ascii[256][16]=
-{
-	/*	0000	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0010	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0020	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0030	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x10,0x10,0x00,0x00},	//33	'!'
-	{0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},	//	'"'
-	{0x00,0x44,0x44,0x44,0xfe,0x44,0x44,0x44,0x44,0x44,0xfe,0x44,0x44,0x44,0x00,0x00},	//	'#'
-	{0x10,0x3a,0x56,0x92,0x92,0x90,0x50,0x38,0x14,0x12,0x92,0x92,0xd4,0xb8,0x10,0x10},	//	'$'
-	{0x62,0x92,0x94,0x94,0x68,0x08,0x10,0x10,0x20,0x2c,0x52,0x52,0x92,0x8c,0x00,0x00},	//	'%'
-	{0x00,0x70,0x88,0x88,0x88,0x90,0x60,0x47,0xa2,0x92,0x8a,0x84,0x46,0x39,0x00,0x00},	//	'&'
-	{0x04,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},	//	'''
-
-	/*	0040	*/
-	{0x02,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x08,0x04,0x02,0x00},	//	'('
-	{0x80,0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x20,0x40,0x80,0x00},	//	')'
-	{0x00,0x00,0x00,0x00,0x00,0x10,0x92,0x54,0x38,0x54,0x92,0x10,0x00,0x00,0x00,0x00},	//	'*'
-	{0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0xfe,0x10,0x10,0x10,0x00,0x00,0x00,0x00},	//	'+'
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x08,0x10},	//	','
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00},	//	'-'
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00},	//	'.'
-	{0x02,0x02,0x04,0x04,0x08,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x80},	//	'/'
-	{0x00,0x18,0x24,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x24,0x18,0x00,0x00},	//48	'0'
-	{0x00,0x08,0x18,0x28,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3e,0x00,0x00},	//	'1'
-
-	/*	0050	*/
-	{0x00,0x18,0x24,0x42,0x42,0x02,0x04,0x08,0x10,0x20,0x20,0x40,0x40,0x7e,0x00,0x00},	//	'2'
-	{0x00,0x18,0x24,0x42,0x02,0x02,0x04,0x18,0x04,0x02,0x02,0x42,0x24,0x18,0x00,0x00},	//	'3'
-	{0x00,0x0c,0x0c,0x0c,0x14,0x14,0x14,0x24,0x24,0x44,0x7e,0x04,0x04,0x1e,0x00,0x00},	//	'4'
-	{0x00,0x7c,0x40,0x40,0x40,0x58,0x64,0x02,0x02,0x02,0x02,0x42,0x24,0x18,0x00,0x00},	//	'5'
-	{0x00,0x18,0x24,0x42,0x40,0x58,0x64,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00},	//	'6'
-	{0x00,0x7e,0x42,0x42,0x04,0x04,0x08,0x08,0x08,0x10,0x10,0x10,0x10,0x38,0x00,0x00},	//	'7'
-	{0x00,0x18,0x24,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x24,0x18,0x00,0x00},	//	'8'
-	{0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x26,0x1a,0x02,0x42,0x24,0x18,0x00,0x00},	//	'9'
-	{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00},	//58	':'
-	{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x08,0x10},	//	';'
-
-	/*	0060	*/
-	{0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x00},	//	'<'
-	{0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00},	//	'='
-	{0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00},	//	'>'
-	{0x00,0x38,0x44,0x82,0x82,0x82,0x04,0x08,0x10,0x10,0x00,0x00,0x18,0x18,0x00,0x00},	//	'?'
-	{0x00,0x38,0x44,0x82,0x9a,0xaa,0xaa,0xaa,0xaa,0xaa,0x9c,0x80,0x46,0x38,0x00,0x00},	//	'@'
-	{0x00,0x18,0x18,0x18,0x18,0x24,0x24,0x24,0x24,0x7e,0x42,0x42,0x42,0xe7,0x00,0x00},	//65	'A'
-	{0x00,0xf0,0x48,0x44,0x44,0x44,0x48,0x78,0x44,0x42,0x42,0x42,0x44,0xf8,0x00,0x00},	//	'B'
-	{0x00,0x3a,0x46,0x42,0x82,0x80,0x80,0x80,0x80,0x80,0x82,0x42,0x44,0x38,0x00,0x00},	//	'C'
-	{0x00,0xf8,0x44,0x44,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x44,0x44,0xf8,0x00,0x00},	//	'D'
-	{0x00,0xfe,0x42,0x42,0x40,0x40,0x44,0x7c,0x44,0x40,0x40,0x42,0x42,0xfe,0x00,0x00},	//	'E'
-
-	/*	0070	*/
-	{0x00,0xfe,0x42,0x42,0x40,0x40,0x44,0x7c,0x44,0x44,0x40,0x40,0x40,0xf0,0x00,0x00},	//	'F'
-	{0x00,0x3a,0x46,0x42,0x82,0x80,0x80,0x9e,0x82,0x82,0x82,0x42,0x46,0x38,0x00,0x00},	//	'G'
-	{0x00,0xe7,0x42,0x42,0x42,0x42,0x42,0x7e,0x42,0x42,0x42,0x42,0x42,0xe7,0x00,0x00},	//	'H'
-	{0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00},	//	'I'
-	{0x00,0x1f,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x84,0x48,0x30,0x00},	//	'J'
-	{0x00,0xe7,0x42,0x44,0x48,0x50,0x50,0x60,0x50,0x50,0x48,0x44,0x42,0xe7,0x00,0x00},	//	'K'
-	{0x00,0xf0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x42,0x42,0xfe,0x00,0x00},	//	'L'
-	{0x00,0xc3,0x42,0x66,0x66,0x66,0x5a,0x5a,0x5a,0x42,0x42,0x42,0x42,0xe7,0x00,0x00},	//	'M'
-	{0x00,0xc7,0x42,0x62,0x62,0x52,0x52,0x52,0x4a,0x4a,0x4a,0x46,0x46,0xe2,0x00,0x00},	//	'N'
-	{0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00,0x00},	//	'O'
-
-	/*	0080	*/
-	{0x00,0xf8,0x44,0x42,0x42,0x42,0x44,0x78,0x40,0x40,0x40,0x40,0x40,0xf0,0x00,0x00},	//	'P'
-	{0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x92,0x8a,0x44,0x3a,0x00,0x00},	//	'Q'
-	{0x00,0xfc,0x42,0x42,0x42,0x42,0x7c,0x44,0x42,0x42,0x42,0x42,0x42,0xe7,0x00,0x00},	//	'R'
-	{0x00,0x3a,0x46,0x82,0x82,0x80,0x40,0x38,0x04,0x02,0x82,0x82,0xc4,0xb8,0x00,0x00},	//	'S'
-	{0x00,0xfe,0x92,0x92,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00},	//	'T'
-	{0x00,0xe7,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x3c,0x00,0x00},	//	'U'
-	{0x00,0xe7,0x42,0x42,0x42,0x42,0x24,0x24,0x24,0x24,0x18,0x18,0x18,0x18,0x00,0x00},	//	'V'
-	{0x00,0xe7,0x42,0x42,0x42,0x5a,0x5a,0x5a,0x5a,0x24,0x24,0x24,0x24,0x24,0x00,0x00},	//	'W'
-	{0x00,0xe7,0x42,0x42,0x24,0x24,0x24,0x18,0x24,0x24,0x24,0x42,0x42,0xe7,0x00,0x00},	//	'X'
-	{0x00,0xee,0x44,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00},	//	'Y'
-
-	/*	0090	*/
-	{0x00,0xfe,0x84,0x84,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x42,0x82,0xfe,0x00,0x00},	//	'Z'
-	{0x00,0x3e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,0x00},	//91	'['
-	{0x80,0x80,0x40,0x40,0x20,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x04,0x02,0x02},	//	'\'
-	{0x00,0x7c,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x7c,0x00},	//	']'
-	{0x00,0x10,0x28,0x44,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},	//	'^'
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00},	//	'_'
-	{0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},	//	'`'
-	{0x00,0x00,0x00,0x00,0x00,0x70,0x08,0x04,0x3c,0x44,0x84,0x84,0x8c,0x76,0x00,0x00},	//97	'a'
-	{0xc0,0x40,0x40,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x42,0x42,0x64,0x58,0x00,0x00},	//	'b'
-	{0x00,0x00,0x00,0x00,0x00,0x30,0x4c,0x84,0x84,0x80,0x80,0x82,0x44,0x38,0x00,0x00},	//	'c'
-
-	/*	0100	*/
-	{0x0c,0x04,0x04,0x04,0x04,0x34,0x4c,0x84,0x84,0x84,0x84,0x84,0x4c,0x36,0x00,0x00},	//	'd'
-	{0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x82,0x82,0xfc,0x80,0x82,0x42,0x3c,0x00,0x00},	//	'e'
-	{0x0e,0x10,0x10,0x10,0x10,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00},	//	'f'
-	{0x00,0x00,0x00,0x00,0x00,0x36,0x4c,0x84,0x84,0x84,0x84,0x4c,0x34,0x04,0x04,0x38},	//	'g'
-	{0xc0,0x40,0x40,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x42,0x42,0x42,0xe3,0x00,0x00},	//	'h'
-	{0x00,0x10,0x10,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00},	//	'i'
-	{0x00,0x04,0x04,0x00,0x00,0x0c,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x08,0x30},	//	'j'
-	{0xc0,0x40,0x40,0x40,0x40,0x4e,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0xe6,0x00,0x00},	//	'k'
-	{0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00},	//	'l'
-	{0x00,0x00,0x00,0x00,0x00,0xf6,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0xdb,0x00,0x00},	//	'm'
-
-	/*	0110	*/
-	{0x00,0x00,0x00,0x00,0x00,0xd8,0x64,0x42,0x42,0x42,0x42,0x42,0x42,0xe3,0x00,0x00},	//	'n'
-	{0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00,0x00},	//	'o'
-	{0x00,0x00,0x00,0x00,0xd8,0x64,0x42,0x42,0x42,0x42,0x42,0x64,0x58,0x40,0x40,0xe0},	//	'p'
-	{0x00,0x00,0x00,0x00,0x34,0x4c,0x84,0x84,0x84,0x84,0x84,0x4c,0x34,0x04,0x04,0x0e},	//	'q'
-	{0x00,0x00,0x00,0x00,0x00,0xdc,0x62,0x42,0x40,0x40,0x40,0x40,0x40,0xe0,0x00,0x00},	//	'r'
-	{0x00,0x00,0x00,0x00,0x00,0x7a,0x86,0x82,0xc0,0x38,0x06,0x82,0xc2,0xbc,0x00,0x00},	//	's'
-	{0x00,0x00,0x10,0x10,0x10,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x0e,0x00,0x00},	//	't'
-	{0x00,0x00,0x00,0x00,0x00,0xc6,0x42,0x42,0x42,0x42,0x42,0x42,0x46,0x3b,0x00,0x00},	//	'u'
-	{0x00,0x00,0x00,0x00,0x00,0xe7,0x42,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x00,0x00},	//	'v'
-	{0x00,0x00,0x00,0x00,0x00,0xe7,0x42,0x42,0x5a,0x5a,0x5a,0x24,0x24,0x24,0x00,0x00},	//	'w'
-
-	/*	0120	*/
-	{0x00,0x00,0x00,0x00,0x00,0xc6,0x44,0x28,0x28,0x10,0x28,0x28,0x44,0xc6,0x00,0x00},	//	'x'
-	{0x00,0x00,0x00,0x00,0x00,0xe7,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x10,0x10,0x60},	//	'y'
-	{0x00,0x00,0x00,0x00,0x00,0xfe,0x82,0x84,0x08,0x10,0x20,0x42,0x82,0xfe,0x00,0x00},	//	'z'
-	{0x00,0x06,0x08,0x10,0x10,0x10,0x10,0x60,0x10,0x10,0x10,0x10,0x08,0x06,0x00,0x00},	//	'{'
-	{0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10},	//	'|'
-	{0x00,0x60,0x10,0x08,0x08,0x08,0x08,0x06,0x08,0x08,0x08,0x08,0x10,0x60,0x00,0x00},	//	'}'
-	{0x00,0x72,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},	//	'~'
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0130	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-
-	/*	0140	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0150	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0160	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0170	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0180	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0190	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0200	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0210	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0220	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0230	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0240	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-	/*	0250~0255	*/
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-
-
-};
-

+ 10 - 14
kernel/src/common/printk.h

@@ -16,29 +16,25 @@
 #define is_digit(c) ((c) >= '0' && (c) <= '9') // 用来判断是否是数字的宏
 
 // 字体颜色的宏定义
-#define WHITE 0x00ffffff  //白
-#define BLACK 0x00000000  //黑
-#define RED 0x00ff0000    //红
-#define ORANGE 0x00ff8000 //橙
-#define YELLOW 0x00ffff00 //黄
-#define GREEN 0x0000ff00  //绿
-#define BLUE 0x000000ff   //蓝
-#define INDIGO 0x0000ffff //靛
-#define PURPLE 0x008000ff //紫
+#define WHITE 0x00ffffff  // 
+#define BLACK 0x00000000  // 
+#define RED 0x00ff0000    // 
+#define ORANGE 0x00ff8000 // 
+#define YELLOW 0x00ffff00 // 
+#define GREEN 0x0000ff00  // 绿
+#define BLUE 0x000000ff   // 
+#define INDIGO 0x0000ffff // 
+#define PURPLE 0x008000ff // 
 
 // 异常的宏定义
 #define EPOS_OVERFLOW 1 // 坐标溢出
 #define EFB_MISMATCH 2  // 帧缓冲区与指定的屏幕大小不匹配
 #define EUNSUPPORTED 3  // 当前操作暂不被支持
 
-#include "font.h"
 #include "glib.h"
-#include <libs/libUI/screen_manager.h>
+#include <libs/lib_ui/screen_manager.h>
 #include <stdarg.h>
 
-extern unsigned char font_ascii[256][16]; //导出ascii字体的bitmap(8*16大小) ps:位于font.h中
-
-
 /**
  * @brief 将字符串按照fmt和args中的内容进行格式化,然后保存到buf中
  *

+ 1 - 1
kernel/src/driver/interrupt/apic/apic.c

@@ -326,7 +326,7 @@ void apic_local_apic_init()
 
     // 检测是否成功启用xAPIC和x2APIC
     if ((eax & 0xc00) == 0xc00)
-        kinfo("xAPIC & x2APIC enabled!");
+        kinfo("xAPIC & x2APIC enabled!\n");
     else if ((eax & 0x800) == 0x800)
         kinfo("Only xAPIC enabled!");
     else

+ 7 - 6
kernel/src/driver/tty/tty_device.rs

@@ -9,9 +9,11 @@ use crate::{
         devfs::{devfs_register, DevFS, DeviceINode},
         vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, Metadata, ROOT_INODE},
     },
-    include::bindings::bindings::{textui_putchar, BLACK, WHITE},
     kerror,
-    libs::rwlock::RwLock,
+    libs::{
+        lib_ui::textui::{textui_putchar, FontColor},
+        rwlock::RwLock,
+    },
     syscall::SystemError,
 };
 
@@ -255,10 +257,9 @@ impl IndexNode for TtyDevice {
                 break;
             }
             // 输出到屏幕
-            unsafe {
-                for x in buf {
-                    textui_putchar(x as u16, WHITE, BLACK);
-                }
+
+            for x in buf {
+                textui_putchar(x as char, FontColor::WHITE, FontColor::BLACK).ok();
             }
         }
         return Ok(());

+ 30 - 13
kernel/src/driver/video/video.c

@@ -17,10 +17,10 @@ extern void rs_register_softirq_video();
 
 uint64_t video_refresh_expire_jiffies = 0;
 uint64_t video_last_refresh_pid = -1;
-
 struct scm_buffer_info_t video_frame_buffer_info = {0};
 static struct multiboot_tag_framebuffer_info_t __fb_info;
-static struct scm_buffer_info_t *video_refresh_target = NULL;
+// static struct scm_buffer_info_t *_video_refresh_target = NULL;
+static struct scm_buffer_info_t video_refresh_target = {0};
 static struct process_control_block *video_daemon_pcb = NULL;
 static spinlock_t daemon_refresh_lock;
 
@@ -35,9 +35,9 @@ void init_frame_buffer()
     kinfo("Re-mapping VBE frame buffer...");
 
     video_frame_buffer_info.vaddr = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + FRAME_BUFFER_MAPPING_OFFSET;
-
     rs_map_phys(video_frame_buffer_info.vaddr, __fb_info.framebuffer_addr, video_frame_buffer_info.size, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
 
+    // kinfo("vaddr:%#018lx", video_frame_buffer_info.vaddr);
     kinfo("VBE frame buffer successfully Re-mapped!");
 }
 
@@ -56,12 +56,16 @@ int video_refresh_daemon(void *unused)
         if (rs_clock() >= video_refresh_expire_jiffies)
         {
 
-            if (likely(video_refresh_target != NULL))
+            if (likely(video_refresh_target.size != 0))
             {
                 spin_lock(&daemon_refresh_lock);
                 if (video_frame_buffer_info.vaddr != NULL)
-                    memcpy((void *)video_frame_buffer_info.vaddr, (void *)video_refresh_target->vaddr,
-                           video_refresh_target->size);
+                {
+                    // kdebug("video_frame_buffer_info.vaddr = %#018lx,get_video_refresh_target_vaddr()= %#018lx" ,video_frame_buffer_info.vaddr,get_video_refresh_target_vaddr());
+
+                    memcpy((void *)video_frame_buffer_info.vaddr, (void *)get_video_refresh_target_vaddr(),
+                           video_refresh_target.size);
+                }
                 spin_unlock(&daemon_refresh_lock);
                 video_daemon_pcb->virtual_runtime =
                     0xfffff0000000; // 临时解决由于显示刷新进程的虚拟运行时间过大/过小,导致其不运行,或者一直运行的问题。将来应使用实时调度解决它
@@ -76,6 +80,10 @@ int video_refresh_daemon(void *unused)
     return 0;
 }
 
+uint64_t get_video_refresh_target_vaddr()
+{
+    return video_refresh_target.vaddr;
+}
 /**
  * @brief 唤醒video的守护进程
  */
@@ -105,10 +113,13 @@ int video_reinitialize(bool level) // 这个函数会在main.c调用, 保证 vid
     {
         rs_unregister_softirq(VIDEO_REFRESH_SIRQ);
         // 计算开始时间
-        video_refresh_expire_jiffies = rs_timer_next_n_ms_jiffies(10 * REFRESH_INTERVAL);
+        video_refresh_expire_jiffies = rs_timer_next_n_ms_jiffies(50 * REFRESH_INTERVAL);
+        kdebug("video_frame_buffer_info.vaddr = %#018lx,get_video_refresh_target_vaddr()= %#018lx", video_frame_buffer_info.vaddr, get_video_refresh_target_vaddr());
 
+        io_mfence();
         // 创建video守护进程
         video_daemon_pcb = kthread_run(&video_refresh_daemon, NULL, "Video refresh daemon");
+        io_mfence();
         video_daemon_pcb->virtual_runtime = 0; // 特殊情况, 最高优先级, 以后再改
         // 启用屏幕刷新软中断
         rs_register_softirq_video();
@@ -123,7 +134,8 @@ int video_reinitialize(bool level) // 这个函数会在main.c调用, 保证 vid
  * @param buf
  * @return int
  */
-int video_set_refresh_target(struct scm_buffer_info_t *buf)
+
+int video_set_refresh_target(struct scm_buffer_info_t buf)
 {
 
     rs_unregister_softirq(VIDEO_REFRESH_SIRQ);
@@ -137,10 +149,11 @@ int video_set_refresh_target(struct scm_buffer_info_t *buf)
     //     rs_usleep(1000);
     // }
     // kdebug("buf = %#018lx", buf);
+
     video_refresh_target = buf;
+
     rs_register_softirq_video();
     kdebug("register softirq video done");
-    // rs_raise_softirq(VIDEO_REFRESH_SIRQ);
 }
 
 /**
@@ -153,8 +166,8 @@ int video_init()
 
     memset(&video_frame_buffer_info, 0, sizeof(struct scm_buffer_info_t));
     memset(&__fb_info, 0, sizeof(struct multiboot_tag_framebuffer_info_t));
-    video_refresh_target = NULL;
-
+    // _video_refresh_target = NULL;
+    video_refresh_target = (struct scm_buffer_info_t){0};
     io_mfence();
     // 从multiboot2获取帧缓冲区信息
     int reserved;
@@ -180,17 +193,21 @@ int video_init()
 
     video_frame_buffer_info.size =
         video_frame_buffer_info.width * video_frame_buffer_info.height * ((video_frame_buffer_info.bit_depth + 7) / 8);
-    // 先临时映射到该地址,稍后再重新映射
-    video_frame_buffer_info.vaddr = 0xffff800003000000;
+    // 先临时映射到50M的位置,稍后再重新映射
+    video_frame_buffer_info.vaddr = 0xffff800003200000;
+
     char init_text1[] = "Video driver to map.\n";
     for (int i = 0; i < sizeof(init_text1) - 1; ++i)
         c_uart_send(COM1, init_text1[i]);
+
     rs_pseudo_map_phys(video_frame_buffer_info.vaddr, __fb_info.framebuffer_addr, video_frame_buffer_info.size);
 
     io_mfence();
     char init_text2[] = "Video driver initialized.\n";
     for (int i = 0; i < sizeof(init_text2) - 1; ++i)
+    {
         c_uart_send(COM1, init_text2[i]);
+    }
 
     return 0;
 }

+ 9 - 7
kernel/src/driver/video/video.h

@@ -1,8 +1,8 @@
 #pragma once
 #include <common/glib.h>
 #include <stdbool.h>
-#include <libs/libUI/screen_manager.h>
-
+#include <libs/lib_ui/screen_manager.h>
+extern struct scm_buffer_info_t video_frame_buffer_info;
 /**
  * @brief 重新初始化显示驱动,需先低级初始化才能高级初始化
  * @param level 初始化等级
@@ -21,13 +21,15 @@ int video_init();
 
 /**
  * @brief 设置帧缓冲区刷新目标
- * 
- * @param buf 
- * @return int 
+ *
+ * @param buf
+ * @return int
  */
-int video_set_refresh_target(struct scm_buffer_info_t *buf);
+// int video_set_refresh_target(struct scm_buffer_info_t *buf);
+int video_set_refresh_target(struct scm_buffer_info_t buf);
 
 extern uint64_t video_refresh_expire_jiffies;
 extern uint64_t video_last_refresh_pid;
 
-void video_refresh_framebuffer(void *data);
+void video_refresh_framebuffer(void *data);
+uint64_t get_video_refresh_target_vaddr();

+ 10 - 2
kernel/src/head.S

@@ -287,8 +287,8 @@ ENTRY(_start64)
     loop .fill_pde_64
 
     // 最低级
-    // 循环 512*50=25600 次,填满50页
-    mov $25600, %ecx
+    // 循环 512*25=12800 次,填满25页,共50M
+    mov $12800, %ecx
     mov $__PT_S, %eax
     mov $0x3, %ebx
 .fill_pt_64:
@@ -297,6 +297,14 @@ ENTRY(_start64)
     add $8, %eax
     loop .fill_pt_64
 
+    // 50-100M填0,共25个页表
+    mov $12800, %ecx
+.fill_pt_64_2:
+    mov $0, 0(%eax)
+    add $8, %eax
+    loop .fill_pt_64_2
+
+
 
 // ==== 加载CR3寄存器
 

+ 1 - 1
kernel/src/include/bindings/wrapper.h

@@ -38,7 +38,7 @@
 #include <exception/gate.h>
 #include <include/DragonOS/refcount.h>
 #include <include/DragonOS/signal.h>
-#include <libs/libUI/textui.h>
+#include <libs/lib_ui/textui.h>
 #include <mm/mm-types.h>
 #include <mm/mm.h>
 #include <mm/mmio.h>

+ 4 - 4
kernel/src/lib.rs

@@ -54,16 +54,16 @@ extern crate thingbuf;
 #[cfg(target_arch = "x86_64")]
 extern crate x86;
 
+use crate::libs::lib_ui::textui::FontColor;
 use crate::mm::allocator::kernel_allocator::KernelAllocator;
 
 // <3>
 use crate::{
-    arch::asm::current::current_pcb,
-    include::bindings::bindings::{process_do_exit, BLACK, GREEN},
+    arch::asm::current::current_pcb, include::bindings::bindings::process_do_exit,
     net::net_core::net_init,
 };
 
-// 声明全局的slab分配器
+// 声明全局的分配器
 #[cfg_attr(not(test), global_allocator)]
 pub static KERNEL_ALLOCATOR: KernelAllocator = KernelAllocator;
 
@@ -106,7 +106,7 @@ pub fn panic(info: &PanicInfo) -> ! {
 /// 该函数用作测试,在process.c的initial_kernel_thread()中调用了此函数
 #[no_mangle]
 pub extern "C" fn __rust_demo_func() -> i32 {
-    printk_color!(GREEN, BLACK, "__rust_demo_func()\n");
+    printk_color!(FontColor::GREEN, FontColor::BLACK, "__rust_demo_func()\n");
     let r = net_init();
     if r.is_err() {
         kwarn!("net_init() failed: {:?}", r.err().unwrap());

+ 1 - 1
kernel/src/libs/Makefile

@@ -1,7 +1,7 @@
 
 CFLAGS += -I .
 
-kernel_lib_subdirs:= libUI sys
+kernel_lib_subdirs:= sys
 
 kernel_lib_objs:= $(shell find ./*.c)
 

+ 0 - 13
kernel/src/libs/libUI/Makefile

@@ -1,13 +0,0 @@
-
-all: screen_manager.o textui.o textui-render.o
-
-CFLAGS += -I .
-
-screen_manager.o: screen_manager.c
-	$(CC) $(CFLAGS) -c screen_manager.c -o screen_manager.o
-
-textui.o: textui.c
-	$(CC) $(CFLAGS) -c textui.c -o textui.o
-
-textui-render.o: textui-render.c
-	$(CC) $(CFLAGS) -c textui-render.c -o textui-render.o

+ 0 - 351
kernel/src/libs/libUI/screen_manager.c

@@ -1,351 +0,0 @@
-#include "screen_manager.h"
-#include <common/kprint.h>
-#include <common/spinlock.h>
-#include <common/string.h>
-#include <driver/multiboot2/multiboot2.h>
-#include <driver/uart/uart.h>
-#include <driver/video/video.h>
-#include <mm/mm.h>
-#include <mm/slab.h>
-
-extern struct scm_buffer_info_t video_frame_buffer_info;
-static struct List scm_framework_list;
-static spinlock_t scm_register_lock;                   // 框架注册锁
-static spinlock_t scm_screen_own_lock = {1};           // 改变屏幕归属者时,需要对该锁加锁
-static struct scm_ui_framework_t *__current_framework; // 当前拥有屏幕控制权的框架
-static uint32_t scm_ui_max_id = 0;
-static bool __scm_alloc_enabled = false;         // 允许动态申请内存的标志位
-static bool __scm_double_buffer_enabled = false; // 允许双缓冲的标志位
-
-/**
- * @brief 创建新的帧缓冲区
- *
- * @param type 帧缓冲区类型
- * @return struct scm_buffer_info_t* 新的帧缓冲区结构体
- */
-static struct scm_buffer_info_t *__create_buffer(uint64_t type)
-{
-    // 若未启用双缓冲,则直接返回帧缓冲区
-    if (unlikely(__scm_double_buffer_enabled == false))
-        return &video_frame_buffer_info;
-
-    struct scm_buffer_info_t *buf = (struct scm_buffer_info_t *)kmalloc(sizeof(struct scm_buffer_info_t), 0);
-    if (buf == NULL)
-        return (void *)-ENOMEM;
-    memset(buf, 0, sizeof(struct scm_buffer_info_t));
-    buf->bit_depth = video_frame_buffer_info.bit_depth;
-    buf->flags = SCM_BF_DB;
-
-    if (type & SCM_BF_PIXEL)
-        buf->flags |= SCM_BF_PIXEL;
-    else
-        buf->flags |= SCM_BF_TEXT;
-    buf->height = video_frame_buffer_info.height;
-    buf->width = video_frame_buffer_info.width;
-    buf->size = video_frame_buffer_info.size;
-
-    void* buf_vaddr = kzalloc(video_frame_buffer_info.size, 0);
-    if (buf_vaddr == NULL)
-        goto failed;
-    buf->vaddr = buf_vaddr;
-    return buf;
-failed:;
-    kfree(buf);
-    return (void *)-ENOMEM;
-}
-
-/**
- * @brief 销毁双缓冲区
- *
- * @param buf
- * @return int
- */
-static int __destroy_buffer(struct scm_buffer_info_t *buf)
-{
-    // 不能销毁帧缓冲区对象
-    if (unlikely(buf == &video_frame_buffer_info || buf == NULL))
-        return -EINVAL;
-    if (unlikely(buf->vaddr == NULL))
-        return -EINVAL;
-    if (unlikely(verify_area(buf->vaddr, buf->size) == true))
-        return -EINVAL;
-    // 是否双缓冲区
-    if (buf->flags & SCM_BF_FB)
-        return -EINVAL;
-
-    // 释放内存页
-    kfree((void*)buf->vaddr);
-    return 0;
-}
-
-/**
- * @brief 初始化屏幕管理模块
- *
- */
-void scm_init()
-{
-    list_init(&scm_framework_list);
-    spin_init(&scm_register_lock);
-    spin_init(&scm_screen_own_lock);
-    io_mfence();
-    scm_ui_max_id = 0;
-    __scm_alloc_enabled = false;         // 禁用动态申请内存
-    __scm_double_buffer_enabled = false; // 禁用双缓冲
-    __current_framework = NULL;
-}
-/**
- * @brief 检查ui框架结构体中的参数设置是否合法
- *
- * @param name 框架名称
- * @param type 框架类型
- * @param ops 框架的操作
- * @return int
- */
-static int __check_ui_param(const char *name, const uint8_t type, const struct scm_ui_framework_operations_t *ops)
-{
-    if (name == NULL)
-        return -EINVAL;
-    if ((type == SCM_FRAMWORK_TYPE_GUI || type == SCM_FRAMWORK_TYPE_TEXT) == 0)
-        return -EINVAL;
-    if (ops == NULL)
-        return -EINVAL;
-    if (ops->install == NULL || ops->uninstall == NULL || ops->enable == NULL || ops->disable == NULL ||
-        ops->change == NULL)
-        return -EINVAL;
-
-    return 0;
-}
-/**
- * @brief 向屏幕管理器注册UI框架(动态获取框架对象结构体)
- *
- * @param name 框架名
- * @param type 类型
- * @param ops 框架操作方法
- * @return int
- */
-int scm_register_alloc(const char *name, const uint8_t type, struct scm_ui_framework_operations_t *ops)
-{
-    // 若未启用动态申请,则返回。
-    if (unlikely(__scm_alloc_enabled == false))
-        return -EAGAIN;
-
-    // 检查参数合法性
-    if (__check_ui_param(name, type, ops) != 0)
-        return -EINVAL;
-
-    struct scm_ui_framework_t *ui = (struct scm_ui_framework_t *)kmalloc(sizeof(struct scm_ui_framework_t *), 0);
-    memset(ui, 0, sizeof(struct scm_ui_framework_t));
-    strncpy(ui->name, name, 15);
-    ui->type = type;
-    ui->ui_ops = ops;
-    list_init(&ui->list);
-
-    spin_lock(&scm_register_lock);
-    ui->id = scm_ui_max_id++;
-    spin_unlock(&scm_register_lock);
-
-    // 创建帧缓冲区
-    ui->buf = __create_buffer(ui->type);
-    if ((uint64_t)(ui->buf) == (uint64_t)-ENOMEM)
-    {
-        kfree(ui);
-        return -ENOMEM;
-    }
-    // 把ui框架加入链表
-    list_add(&scm_framework_list, &ui->list);
-
-    // 调用ui框架的回调函数以安装ui框架,并将其激活
-    ui->ui_ops->install(ui->buf);
-    ui->ui_ops->enable(NULL);
-    if (__current_framework == NULL)
-        return scm_framework_enable(ui);
-    return 0;
-}
-
-/**
- * @brief 向屏幕管理器注册UI框架(静态设置的框架对象)
- *
- * @param ui 框架结构体指针
- * @return int 错误码
- */
-int scm_register(struct scm_ui_framework_t *ui)
-{
-    if (ui == NULL)
-        return -EINVAL;
-    if (__check_ui_param(ui->name, ui->type, ui->ui_ops) != 0)
-        return -EINVAL;
-
-    list_init(&ui->list);
-    spin_lock(&scm_register_lock);
-    ui->id = scm_ui_max_id++;
-    spin_unlock(&scm_register_lock);
-
-    ui->buf = __create_buffer(ui->type);
-
-    if ((uint64_t)(ui->buf) == (uint64_t)-ENOMEM)
-        return -ENOMEM;
-
-    // 把ui框架加入链表
-    list_add(&scm_framework_list, &ui->list);
-
-    // 调用ui框架的回调函数以安装ui框架,并将其激活
-    ui->ui_ops->install(ui->buf);
-    ui->ui_ops->enable(NULL);
-
-    if (__current_framework == NULL)
-        return scm_framework_enable(ui);
-
-    return 0;
-}
-
-/**
- * @brief 向屏幕管理器卸载UI框架
- *
- * @param ui ui框架结构体
- * @return int
- */
-int scm_unregister(struct scm_ui_framework_t *ui)
-{
-    return 0;
-}
-
-/**
- * @brief 向屏幕管理器卸载动态创建的UI框架
- *
- * @param ui ui框架结构体
- * @return int
- */
-int scm_unregister_alloc(struct scm_ui_framework_t *ui)
-{
-    return 0;
-}
-
-/**
- * @brief 允许动态申请内存
- *
- * @return int
- */
-int scm_enable_alloc()
-{
-    __scm_alloc_enabled = true;
-    return 0;
-}
-
-/**
- * @brief 允许双缓冲区
- *
- * @return int
- */
-int scm_enable_double_buffer()
-{
-    if (__scm_double_buffer_enabled == true) // 已经开启了双缓冲区了, 直接退出
-        return 0;
-    __scm_double_buffer_enabled = true;
-    if (list_empty(&scm_framework_list)) // scm 框架链表为空
-        return 0;
-
-    // 逐个检查已经注册了的ui框架,将其缓冲区更改为双缓冲
-    struct scm_ui_framework_t *ptr = container_of(list_next(&scm_framework_list), struct scm_ui_framework_t, list);
-    // 这里的ptr不需要特判空指针吗 问题1
-    do
-    {
-        if (ptr->buf == &video_frame_buffer_info)
-        {
-            c_uart_send_str(COM1, "##init double buffer##\n");
-            struct scm_buffer_info_t *buf = __create_buffer(SCM_BF_DB | SCM_BF_PIXEL);
-            if ((uint64_t)(buf) == (uint64_t)-ENOMEM)
-                return -ENOMEM;
-            c_uart_send_str(COM1, "##to change double buffer##\n");
-
-            if (ptr->ui_ops->change(buf) != 0) // 这里的change回调函数不会是空指针吗 问题2
-            {
-
-                __destroy_buffer(buf);
-                kfree(buf);
-            }
-        }
-
-    } while (list_next(&ptr->list) != &scm_framework_list); // 枚举链表的每一个ui框架
-
-    // 设置定时刷新的对象
-    video_set_refresh_target(__current_framework->buf);
-    // 通知显示驱动,启动双缓冲
-    video_reinitialize(true);
-    return 0;
-}
-
-/**
- * @brief 启用某个ui框架,将它的帧缓冲区渲染到屏幕上
- *
- * @param ui 要启动的ui框架
- * @return int 返回码
- */
-int scm_framework_enable(struct scm_ui_framework_t *ui)
-{
-    if (ui->buf->vaddr == NULL)
-        return -EINVAL;
-    spin_lock(&scm_screen_own_lock);
-    int retval = 0;
-    if (__scm_double_buffer_enabled == true)
-    {
-
-        retval = video_set_refresh_target(ui->buf);
-        if (retval == 0)
-            __current_framework = ui;
-    }
-    else
-        __current_framework = ui;
-    ui->ui_ops->enable(NULL);
-    spin_unlock(&scm_screen_own_lock);
-    return retval;
-}
-
-/**
- * @brief 禁用某个ui框架,将它的帧缓冲区从屏幕上移除
- *
- * @param ui 要禁用的ui框架
- * @return int 返回码
- */
-int scm_framework_disable(struct scm_ui_framework_t *ui)
-{
-    if (ui->buf->vaddr == NULL)
-        return -EINVAL;
-    spin_lock(&scm_screen_own_lock);
-    if (ui != __current_framework)
-        return -EINVAL;
-    int retval = 0;
-    if (__scm_double_buffer_enabled == true)
-    {
-        retval = video_set_refresh_target(NULL);
-        if (retval == 0)
-            __current_framework = NULL;
-    }
-    else
-        __current_framework = NULL;
-
-    ui->ui_ops->disable(NULL);
-    spin_unlock(&scm_screen_own_lock);
-    return retval;
-}
-
-/**
- * @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题
- *
- */
-void scm_reinit()
-{
-    scm_enable_alloc();
-    // video_reinitialize(false);
-
-    // 遍历当前所有使用帧缓冲区的框架,更新地址
-    // 逐个检查已经注册了的ui框架,将其缓冲区更改为双缓冲
-    struct scm_ui_framework_t *ptr = container_of(list_next(&scm_framework_list), struct scm_ui_framework_t, list);
-    do
-    {
-        if (ptr->buf == &video_frame_buffer_info)
-        {
-            ptr->ui_ops->change(&video_frame_buffer_info);
-        }
-    } while (list_next(&ptr->list) != &scm_framework_list);
-    return;
-}

+ 0 - 120
kernel/src/libs/libUI/screen_manager.h

@@ -1,120 +0,0 @@
-#pragma once
-#include <common/sys/types.h>
-#include <common/glib.h>
-
-// 帧缓冲区标志位
-#define SCM_BF_FB (1 << 0)    // 当前buffer是设备显存中的帧缓冲区
-#define SCM_BF_DB (1 << 1)    // 当前buffer是双缓冲
-#define SCM_BF_TEXT (1 << 2)  // 使用文本模式
-#define SCM_BF_PIXEL (1 << 3) // 使用图像模式
-
-// ui框架类型
-#define SCM_FRAMWORK_TYPE_TEXT (uint8_t)0
-#define SCM_FRAMWORK_TYPE_GUI (uint8_t)1
-
-/**
- * @brief 帧缓冲区信息结构体
- *
- */
-struct scm_buffer_info_t
-{
-    uint32_t width;     // 帧缓冲区宽度(pixel或columns)
-    uint32_t height;    // 帧缓冲区高度(pixel或lines)
-    uint32_t size;      // 帧缓冲区大小(bytes)
-    uint32_t bit_depth; // 像素点位深度
-
-    uint64_t vaddr; // 帧缓冲区的地址
-    uint64_t flags; // 帧缓冲区标志位
-};
-
-/**
- * @brief 上层ui框架应当实现的接口
- *
- */
-struct scm_ui_framework_operations_t
-{
-    int (*install)(struct scm_buffer_info_t *buf); // 安装ui框架的回调函数
-    int (*uninstall)(void *args);                  // 卸载ui框架的回调函数
-    int (*enable)(void *args);                     // 启用ui框架的回调函数
-    int (*disable)(void *args);                    // 禁用ui框架的回调函数
-    int (*change)(struct scm_buffer_info_t *buf);  // 改变ui框架的帧缓冲区的回调函数
-};
-struct scm_ui_framework_t
-{
-    struct List list;
-    uint16_t id;
-    char name[16];
-    uint8_t type;
-    struct scm_ui_framework_operations_t *ui_ops;
-    struct scm_buffer_info_t *buf;
-};
-
-/**
- * @brief 初始化屏幕管理模块
- *
- */
-void scm_init();
-
-/**
- * @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题
- * 
- */
-void scm_reinit();
-
-/**
- * @brief 向屏幕管理器注册UI框架(动态获取框架对象结构体)
- *
- * @param name 框架名
- * @param type 类型
- * @param ops 框架操作方法
- * @return int
- */
-int scm_register_alloc(const char *name, const uint8_t type, struct scm_ui_framework_operations_t *ops);
-
-/**
- * @brief 向屏幕管理器注册UI框架(静态设置的框架对象)
- *
- * @param ui 框架结构体指针
- * @return int 错误码
- */
-int scm_register(struct scm_ui_framework_t *ui);
-
-/**
- * @brief 向屏幕管理器卸载UI框架
- *
- * @param ui ui框架结构体
- * @return int
- */
-int scm_unregister(struct scm_ui_framework_t *ui);
-
-/**
- * @brief 向屏幕管理器卸载动态创建的UI框架
- *
- * @param ui ui框架结构体
- * @return int
- */
-int scm_unregister_alloc(struct scm_ui_framework_t *ui);
-
-/**
- * @brief 允许动态申请内存
- *
- * @return int
- */
-int scm_enable_alloc();
-
-/**
- * @brief 允许双缓冲区
- *
- * @return int
- */
-int scm_enable_double_buffer();
-
-/**
- * @brief 启用某个ui框架,将它的帧缓冲区渲染到屏幕上
- *
- * @param ui 要启动的ui框架
- * @return int 返回码
- */
-int scm_framework_enable(struct scm_ui_framework_t *ui);
-
-int scm_framework_disable(struct scm_ui_framework_t *ui);

+ 0 - 154
kernel/src/libs/libUI/textui-render.c

@@ -1,154 +0,0 @@
-#include "textui.h"
-#include <driver/uart/uart.h>
-#include <common/errno.h>
-#include "screen_manager.h"
-
-#define WHITE 0x00ffffff  //白
-#define BLACK 0x00000000  //黑
-#define RED 0x00ff0000    //红
-#define ORANGE 0x00ff8000 //橙
-#define YELLOW 0x00ffff00 //黄
-#define GREEN 0x0000ff00  //绿
-#define BLUE 0x000000ff   //蓝
-#define INDIGO 0x0000ffff //靛
-#define PURPLE 0x008000ff //紫
-
-// 根据rgb计算出最终的颜色值
-#define calculate_color(r, g, b) ((((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff)) & 0x00ffffff)
-
-extern struct scm_ui_framework_t textui_framework;
-
-extern unsigned char font_ascii[256][16]; //导出ascii字体的bitmap(8*16大小) ps:位于font.h中
-static void __textui_render_chromatic(uint16_t actual_line, uint16_t index, struct textui_char_chromatic_t *character);
-
-/**
- * @brief 重新渲染整个虚拟行
- *
- * @param window 窗口结构体
- * @param vline_id 虚拟行号
- * @return int 错误码
- */
-int textui_refresh_vline(struct textui_window_t *window, uint16_t vline_id)
-{
-    if (textui_is_chromatic(window->flags))
-        return textui_refresh_characters(window, vline_id, 0, window->chars_per_line);
-    else
-        return textui_refresh_characters(window, vline_id, 0, window->chars_per_line);
-}
-
-int textui_refresh_vlines(struct textui_window_t *window, uint16_t start, uint16_t count)
-{
-    char bufff[16] = {0};
-    // uart_send_str(COM1, "  BEGIN  ");
-    for (int i = start; i < window->vlines_num && count > 0; ++i, --count)
-    {
-        // sprintk(bufff, "[ 1fresh: %d ] ", i);
-        // uart_send_str(COM1, bufff);
-        textui_refresh_vline(window, i);
-    }
-    start = 0;
-    while (count > 0)
-    {
-        // sprintk(bufff, "[ 2fresh: %d ] ", start);
-        // uart_send_str(COM1, bufff);
-        // sprintk(bufff, " index=%d ", (window->vlines.chromatic)[start].index);
-        // uart_send_str(COM1, bufff);
-        textui_refresh_vline(window, start);
-        ++start;
-        --count;
-    }
-    // uart_send_str(COM1, "  END  ");
-    return 0;
-}
-
-/**
- * @brief 刷新某个虚拟行的连续n个字符对象
- *
- * @param window 窗口结构体
- * @param vline_id 虚拟行号
- * @param start 起始字符号
- * @param count 要刷新的字符数量
- * @return int 错误码
- */
-int textui_refresh_characters(struct textui_window_t *window, uint16_t vline_id, uint16_t start, uint16_t count)
-{
-    if (window->id != __textui_get_current_window_id())
-        return 0;
-    // 判断虚拟行参数是否合法
-    if (unlikely(vline_id >= window->vlines_num && (start + count) > window->chars_per_line))
-        return -EINVAL;
-
-    // 计算虚拟行对应的真实行
-    int actual_line_id = (int)vline_id - window->top_vline;
-    if (actual_line_id < 0)
-        actual_line_id += __textui_get_actual_lines();
-    // 判断真实行id是否合理
-    if (unlikely(actual_line_id < 0 || actual_line_id >= __textui_get_actual_lines()))
-        return 0;
-
-    // 若是彩色像素模式
-    if (textui_is_chromatic(window->flags))
-    {
-        struct textui_vline_chromatic_t *vline = &(window->vlines.chromatic)[vline_id];
-        for (int i = 0; i < count; ++i)
-        {
-
-            __textui_render_chromatic(actual_line_id, start + i, &vline->chars[start + i]);
-        }
-    }
-
-    return 0;
-}
-
-/**
- * @brief 渲染彩色字符
- *
- * @param actual_line 真实行的行号
- * @param index 列号
- * @param character 要渲染的字符
- */
-static void __textui_render_chromatic(uint16_t actual_line, uint16_t index, struct textui_char_chromatic_t *character)
-{
-    /**
-     * @brief 在屏幕上指定位置打印字符
-     *
-     * @param x 左上角列像素点位置
-     * @param y 左上角行像素点位置
-     * @param FRcolor 字体颜色
-     * @param BKcolor 背景颜色
-     * @param font 字符的bitmap
-     */
-
-    unsigned char *font_ptr = font_ascii[(uint8_t)character->c];
-    unsigned int *addr;
-    uint32_t *fb = (uint32_t *)textui_framework.buf->vaddr;
-
-    uint32_t FRcolor = character->FRcolor & 0x00ffffff;
-
-    uint32_t BKcolor = character->BKcolor & 0x00ffffff;
-
-    uint32_t x = index * TEXTUI_CHAR_WIDTH;
-    uint32_t y = actual_line * TEXTUI_CHAR_HEIGHT;
-
-    int testbit; // 用来测试某位是背景还是字体本身
-
-    for (int i = 0; i < TEXTUI_CHAR_HEIGHT; ++i)
-    {
-        // 计算出帧缓冲区的地址
-        addr = (uint32_t *)(fb + textui_framework.buf->width * (y + i) + x);
-
-        testbit = (1 << (TEXTUI_CHAR_WIDTH + 1));
-        for (int j = 0; j < TEXTUI_CHAR_WIDTH; ++j)
-        {
-            // 从左往右逐个测试相应位
-            testbit >>= 1;
-            if (*font_ptr & testbit)
-                *addr = FRcolor; // 字,显示前景色
-            else
-                *addr = BKcolor; // 背景色
-
-            ++addr;
-        }
-        ++font_ptr;
-    }
-}

+ 0 - 372
kernel/src/libs/libUI/textui.c

@@ -1,372 +0,0 @@
-#include "textui.h"
-
-#include <driver/uart/uart.h>
-#include "screen_manager.h"
-#include <common/atomic.h>
-#include <common/errno.h>
-#include <common/printk.h>
-#include <common/string.h>
-
-struct scm_ui_framework_t textui_framework;
-static spinlock_t __window_id_lock = {1};
-static uint32_t __window_max_id = 0;
-
-// 暂时初始化16080个初始字符对象以及67个虚拟行对象
-#define INITIAL_CHARS 16080
-#define INITIAL_VLINES (int)(1080 / 16)
-static struct textui_char_chromatic_t __initial_chars[INITIAL_CHARS] = {0};
-static struct textui_vline_chromatic_t __initial_vlines[INITIAL_VLINES] = {0};
-static struct textui_window_t __initial_window = {0}; // 初始窗口
-static struct textui_private_info_t __private_info = {0};
-static struct List __windows_list;
-static spinlock_t change_lock;
-
-// 用于标记是否允许输出到屏幕
-static atomic_t __put_window_enable_flag = {1};
-
-/**
- * @brief 初始化window对象
- *
- * @param window 窗口对象
- * @param flags 标志位
- * @param vlines_num 虚拟行的总数
- * @param vlines_ptr 虚拟行数组指针
- * @param cperline 每行最大的字符数
- */
-static int __textui_init_window(struct textui_window_t *window, uint8_t flags, uint16_t vlines_num, void *vlines_ptr,
-                                uint16_t cperline)
-{
-    memset((window), 0, sizeof(struct textui_window_t));
-    list_init(&(window)->list);
-    window->lock.lock = 1;
-    spin_lock(&__window_id_lock);
-    window->id = __window_max_id++;
-    spin_unlock(&__window_id_lock);
-    window->flags = flags;
-    window->vlines_num = vlines_num;
-    window->vlines_used = 1;
-    window->top_vline = 0;
-    window->vline_operating = 0;
-    window->chars_per_line = cperline;
-    if (textui_is_chromatic(flags))
-        window->vlines.chromatic = vlines_ptr;
-    else
-        window->vlines.normal = vlines_ptr;
-    list_add(&__windows_list, &(window)->list);
-}
-
-/**
- * @brief 初始化虚拟行对象
- *
- * @param vline 虚拟行对象指针
- * @param chars_ptr 字符对象数组指针
- */
-#define __textui_init_vline(vline, chars_ptr)                                                                          \
-    do                                                                                                                 \
-    {                                                                                                                  \
-        memset(vline, 0, sizeof(struct textui_vline_chromatic_t));                                                     \
-        (vline)->index = 0;                                                                                            \
-        (vline)->chars = chars_ptr;                                                                                    \
-    } while (0)
-
-int textui_install_handler(struct scm_buffer_info_t *buf)
-{
-    // return printk_init(buf);
-    c_uart_send_str(COM1, "textui_install_handler\n");
-    return 0;
-}
-
-int textui_uninstall_handler(void *args)
-{
-    return 0;
-}
-
-int textui_enable_handler(void *args)
-{
-    c_uart_send_str(COM1, "textui_enable_handler\n");
-    atomic_cmpxchg(&__put_window_enable_flag, 0, 1);
-    return 0;
-}
-
-int textui_disable_handler(void *args)
-{
-    c_uart_send_str(COM1, "textui_disable_handler\n");
-    atomic_set(&__put_window_enable_flag, 0);
-    return 0;
-}
-
-int textui_change_handler(struct scm_buffer_info_t *buf)
-{
-    memcpy((void *)buf->vaddr, (void *)(textui_framework.buf->vaddr), textui_framework.buf->size);
-    textui_framework.buf = buf;
-    
-    return 0;
-}
-
-struct scm_ui_framework_operations_t textui_ops = {
-    .install = &textui_install_handler,
-    .uninstall = &textui_uninstall_handler,
-    .change = &textui_change_handler,
-    .enable = &textui_enable_handler,
-    .disable = &textui_disable_handler,
-};
-
-/**
- * @brief 获取textui的帧缓冲区能容纳的内容的行数
- *
- * @return uint16_t
- */
-uint16_t __textui_get_actual_lines()
-{
-    return __private_info.actual_line;
-}
-
-/**
- * @brief 获取当前渲染的窗口的id
- *
- * @return uint16_t
- */
-uint32_t __textui_get_current_window_id()
-{
-    return __private_info.current_window->id;
-}
-
-/**
- * @brief 插入换行
- *
- * @param window 窗口结构体
- * @param vline_id 虚拟行号
- * @return int
- */
-static int __textui_new_line(struct textui_window_t *window, uint16_t vline_id)
-{
-    // todo: 支持在两个虚拟行之间插入一个新行
-
-    ++window->vline_operating;
-
-    if (unlikely(window->vline_operating == window->vlines_num))
-        window->vline_operating = 0;
-    struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
-    memset(vline->chars, 0, sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
-    vline->index = 0;
-
-    if (likely(window->vlines_used == window->vlines_num)) // 需要滚动屏幕
-    {
-
-        ++window->top_vline;
-
-        if (unlikely(window->top_vline >= window->vlines_num))
-            window->top_vline = 0;
-
-        // 刷新所有行
-        textui_refresh_vlines(window, window->top_vline, window->vlines_num);
-    }
-    else
-        ++window->vlines_used;
-
-    return 0;
-}
-
-/**
- * @brief 真正向屏幕上输出字符的函数
- *
- * @param window
- * @param character
- * @return int
- */
-static int __textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor,
-                                   uint32_t BKcolor)
-{
-    if (textui_is_chromatic(window->flags)) // 启用彩色字符
-    {
-        struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
-
-        vline->chars[vline->index].c = character;
-        vline->chars[vline->index].FRcolor = FRcolor & 0xffffff;
-        vline->chars[vline->index].BKcolor = BKcolor & 0xffffff;
-        ++vline->index;
-        textui_refresh_characters(window, window->vline_operating, vline->index - 1, 1);
-        // 换行
-        // 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行
-        if (vline->index > window->chars_per_line)
-        {
-            __textui_new_line(window, window->vline_operating);
-        }
-    }
-    else
-    {
-        // todo: 支持纯文本字符
-        while (1)
-            pause();
-    }
-    return 0;
-}
-
-/**
- * @brief 在指定窗口上输出一个字符
- *
- * @param window 窗口
- * @param character 字符
- * @param FRcolor 前景色(RGB)
- * @param BKcolor 背景色(RGB)
- * @return int
- */
-int textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor, uint32_t BKcolor)
-{
-    if (unlikely(character == '\0'))
-        return 0;
-    if (!textui_is_chromatic(window->flags)) // 暂不支持纯文本窗口
-        return 0;
-
-    // uint64_t rflags = 0; // 加锁后rflags存储到这里
-    spin_lock_no_preempt(&window->lock);
-    c_uart_send(COM1, character);
-    // 如果禁止输出,直接返回
-    if(atomic_read(&__put_window_enable_flag) == 0)
-    {
-        spin_unlock_no_preempt(&window->lock);
-        return 0;
-    }
-
-    if (unlikely(character == '\n'))
-    {
-        // 换行时还需要输出\r
-        c_uart_send(COM1, '\r');
-        __textui_new_line(window, window->vline_operating);
-        // spin_unlock_irqrestore(&window->lock, rflags);
-        spin_unlock_no_preempt(&window->lock);
-        return 0;
-    }
-    else if (character == '\t') // 输出制表符
-    {
-        int space_to_print = 8 - window->vlines.chromatic[window->vline_operating].index % 8;
-
-        while (space_to_print--)
-        {
-            __textui_putchar_window(window, ' ', FRcolor, BKcolor);
-        }
-    }
-    else if (character == '\b') // 退格
-    {
-        char bufff[128] = {0};
-        --(window->vlines.chromatic[window->vline_operating].index);
-        {
-            uint16_t tmp = window->vlines.chromatic[window->vline_operating].index;
-            if (tmp >= 0)
-            {
-                window->vlines.chromatic[window->vline_operating].chars[tmp].c = ' ';
-                window->vlines.chromatic[window->vline_operating].chars[tmp].BKcolor = BKcolor & 0xffffff;
-                textui_refresh_characters(window, window->vline_operating, tmp, 1);
-            }
-        }
-        // 需要向上缩一行
-        if (window->vlines.chromatic[window->vline_operating].index <= 0)
-        {
-            window->vlines.chromatic[window->vline_operating].index = 0;
-            memset(window->vlines.chromatic[window->vline_operating].chars, 0,
-                   sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
-            --(window->vline_operating);
-            if (unlikely(window->vline_operating < 0))
-                window->vline_operating = window->vlines_num - 1;
-
-            // 考虑是否向上滚动
-            if (likely(window->vlines_used > __private_info.actual_line))
-            {
-                --window->top_vline;
-                if (unlikely(window->top_vline < 0))
-                    window->top_vline = window->vlines_num - 1;
-            }
-            --window->vlines_used;
-            textui_refresh_vlines(window, window->top_vline, __private_info.actual_line);
-        }
-    }
-    else
-    {
-        if (window->vlines.chromatic[window->vline_operating].index == window->chars_per_line)
-            __textui_new_line(window, window->vline_operating);
-        __textui_putchar_window(window, character, FRcolor, BKcolor);
-    }
-
-    // spin_unlock_irqrestore(&window->lock, rflags);
-    spin_unlock_no_preempt(&window->lock);
-    return 0;
-}
-
-/**
- * @brief 在默认窗口上输出一个字符
- *
- * @param character 字符
- * @param FRcolor 前景色(RGB)
- * @param BKcolor 背景色(RGB)
- * @return int
- */
-int textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor)
-{
-
-    return textui_putchar_window(__private_info.default_window, character, FRcolor, BKcolor);
-}
-
-/**
- * @brief 初始化text ui框架
- *
- * @return int 
- */
-int textui_init()
-{
-    spin_init(&change_lock);
-
-    spin_init(&__window_id_lock);
-    __window_max_id = 0;
-    list_init(&__windows_list);
-    memset(&textui_framework, 0, sizeof(struct scm_ui_framework_t));
-    memset(&__private_info, 0, sizeof(struct textui_private_info_t));
-
-    io_mfence();
-    char name[] = "textUI";
-    strcpy(textui_framework.name, name);
-
-    textui_framework.ui_ops = &textui_ops;
-    textui_framework.type = 0;
-
-    // 注册框架到屏幕管理器
-    int retval = scm_register(&textui_framework);
-    if (retval != 0)
-    {
-        c_uart_send_str(COM1, "text ui init failed\n");
-        while (1)
-            pause();
-    }
-
-    uint16_t chars_per_vline = textui_framework.buf->width / TEXTUI_CHAR_WIDTH;
-    uint16_t total_vlines = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
-    int cnt = chars_per_vline * total_vlines;
-
-    struct textui_vline_chromatic_t *vl_ptr = __initial_vlines;
-    struct textui_char_chromatic_t *ch_ptr = __initial_chars;
-
-    // 初始化虚拟行
-    for (int i = 0; i < total_vlines; ++i)
-    {
-        __textui_init_vline((vl_ptr + i), (ch_ptr + i * chars_per_vline));
-    }
-
-    // 初始化窗口
-    __textui_init_window((&__initial_window), TEXTUI_WF_CHROMATIC, total_vlines, __initial_vlines, chars_per_vline);
-    __private_info.current_window = &__initial_window;
-    __private_info.default_window = &__initial_window;
-    __private_info.actual_line = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
-
-    c_uart_send_str(COM1, "text ui initialized\n");
-    return 0;
-}
-
-
-void enable_textui()
-{
-    scm_framework_enable(&textui_framework);
-}
-
-void disable_textui()
-{
-    scm_framework_disable(&textui_framework);
-}

+ 0 - 187
kernel/src/libs/libUI/textui.h

@@ -1,187 +0,0 @@
-#pragma once
-#include <common/glib.h>
-#include <common/sys/types.h>
-#include <common/spinlock.h>
-
-/*
-textui中的几个对象的关系:
-
-
-                                          textui_vline_normal_t
-                                          +--------------------------------+
-                                          |                                |        textui_char_normal_t
- textui_window_t                          | chars: textui_char_normal_t *  |        +--------------------------+
-+----------------------------+            |                                |        |                          |
-|                            |     +------>                                +-------->  c: char                 |
-|  list:List                 |     |      | index:  int16_t                |        +--------------------------+
-|  vlines_num:int16_t        |     |      |                                |
-|  vlines_used:int16_t       |     |      +--------------------------------+
-|                            |     |
-|  vlines                    +-----+                                                textui_char_chromatic_t
-|                            |     |       textui_vline_chromatic_t                 +--------------------------+
-|  top_vline:int16_t         |     |      +-------------------------------------+   |                          |
-|  vline_operating:int16_t   |     |      |                                     |   |   c: uint16_t            |
-|  chars_per_line:int16_t    |     |      |  chars: textui_char_chromatic_t *   |   |                          |
-|  flags:uint8_t             |     |      |                                     |   |   FRcolor:24             |
-|  lock:spinlock_t           |     +------>                                     +--->                          |
-|                            |            |  index:  int16_t                    |   |   BKcolor:24             |
-|                            |            |                                     |   |                          |
-+----------------------------+            +-------------------------------------+   +--------------------------+
- */
-
-// 文本窗口标志位
-// 文本窗口是否为彩色
-#define TEXTUI_WF_CHROMATIC (1 << 0)
-
-// 窗口是否启用彩色字符
-#define textui_is_chromatic(flag) ((flag)&TEXTUI_WF_CHROMATIC)
-
-// 每个字符的宽度和高度(像素)
-#define TEXTUI_CHAR_WIDTH 8
-#define TEXTUI_CHAR_HEIGHT 16
-
-/**
- * @brief 黑白字符对象
- *
- */
-struct textui_char_normal_t
-{
-    char c;
-};
-
-/**
- * @brief 彩色字符对象
- *
- */
-struct textui_char_chromatic_t
-{
-    unsigned c : 16;
-
-    // 前景色
-    unsigned FRcolor : 24; // rgb
-
-    // 背景色
-    unsigned BKcolor : 24; // rgb
-};
-
-// 注意!!! 请保持vline结构体的大小、成员变量命名相等!
-/**
- * @brief 单色显示的虚拟行结构体
- *
- */
-struct textui_vline_normal_t
-{
-    struct textui_char_normal_t *chars; // 字符对象数组
-    int16_t index;                      // 当前操作的位置
-};
-
-/**
- * @brief 彩色显示的虚拟行结构体
- *
- */
-struct textui_vline_chromatic_t
-{
-    struct textui_char_chromatic_t *chars;
-    int16_t index; // 当前操作的位置
-};
-
-/**
- * @brief textu ui 框架的文本窗口结构体
- *
- */
-struct textui_window_t
-{
-    struct List list;
-
-    uint32_t id;         // 窗口id
-    int16_t vlines_num;  // 虚拟行总数
-    int16_t vlines_used; // 当前已经使用了的虚拟行总数
-
-    // 指向虚拟行的数组的指针(二选一)
-    union
-    {
-        struct textui_vline_normal_t *normal;
-        struct textui_vline_chromatic_t *chromatic;
-    } vlines;
-
-    int16_t top_vline;       // 位于最顶上的那一个虚拟行的行号
-    int16_t vline_operating; // 正在操作的vline
-    int16_t chars_per_line;  // 每行最大容纳的字符数
-    uint8_t flags;           // 窗口flag
-    spinlock_t lock;         // 窗口操作锁
-};
-
-struct textui_private_info_t
-{
-    int16_t actual_line;                    // 真实行的数量
-    struct textui_window_t *current_window; // 当前的主窗口
-    struct textui_window_t *default_window; // 默认print到的窗口
-};
-
-/**
- * @brief 重新渲染整个虚拟行
- *
- * @param window 窗口结构体
- * @param vline_id 虚拟行号
- * @return int 错误码
- */
-int textui_refresh_vline(struct textui_window_t *window, uint16_t vline_id);
-
-int textui_refresh_vlines(struct textui_window_t *window, uint16_t start, uint16_t count);
-
-/**
- * @brief 刷新某个虚拟行的连续n个字符对象
- *
- * @param window 窗口结构体
- * @param vline_id 虚拟行号
- * @param start 起始字符号
- * @param count 要刷新的字符数量
- * @return int 错误码
- */
-int textui_refresh_characters(struct textui_window_t *window, uint16_t vline_id, uint16_t start, uint16_t count);
-
-/**
- * @brief 在指定窗口上输出一个字符
- *
- * @param window 窗口
- * @param character 字符
- * @param FRcolor 前景色(RGB)
- * @param BKcolor 背景色(RGB)
- * @return int
- */
-int textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor, uint32_t BKcolor);
-
-/**
- * @brief 在默认窗口上输出一个字符
- *
- * @param character 字符
- * @param FRcolor 前景色(RGB)
- * @param BKcolor 背景色(RGB)
- * @return int
- */
-int textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor);
-
-/**
- * @brief 获取textui的帧缓冲区能容纳的内容的行数
- *
- * @return uint16_t
- */
-uint16_t __textui_get_actual_lines();
-
-/**
- * @brief 获取当前渲染的窗口的id
- *
- * @return uint16_t
- */
-uint32_t __textui_get_current_window_id();
-
-/**
- * @brief 初始化text ui框架
- *
- * @return int
- */
-int textui_init();
-
-void enable_textui();
-
-void disable_textui();

BIN
kernel/src/libs/lib_ui/font/binaries/spleen-8x16.raw_bytes


+ 90 - 0
kernel/src/libs/lib_ui/font/mod.rs

@@ -0,0 +1,90 @@
+use super::textui::GlyphMapping;
+
+pub mod spleen_font;
+
+pub use spleen_font::SPLEEN_FONT_8x16 as FONT_8x16;
+
+/// Stores the font bitmap and some additional info for each font.
+#[derive(Clone, Copy)]
+pub struct BitmapFont<'a> {
+    /// The raw bitmap data for the font.
+    bitmap: RawBitMap<'a>,
+
+    /// The char to glyph mapping.
+    glyph_mapping: &'a dyn GlyphMapping,
+
+    /// The size of each character in the raw bitmap data.
+    size: Size,
+
+    bytes_per_char: usize,
+}
+
+#[allow(dead_code)]
+impl<'a> BitmapFont<'a> {
+    pub const fn new(
+        bitmap: RawBitMap<'a>,
+        glyph_mapping: &'a dyn GlyphMapping,
+        size: Size,
+    ) -> Self {
+        Self {
+            bitmap,
+            glyph_mapping,
+            size,
+            bytes_per_char: (size.width + 7) / 8 * size.height,
+        }
+    }
+    /// Return the width of each character.
+    pub const fn width(&self) -> u32 {
+        self.size.width as u32
+    }
+
+    /// Return the height of each character.
+    pub const fn height(&self) -> u32 {
+        self.size.height as u32
+    }
+
+    #[inline(always)]
+    pub fn char_map(&self, character: char) -> &'a [u8] {
+        let index = self.glyph_mapping.index(character);
+        let pos = index * self.bytes_per_char;
+
+        return &self.bitmap.data[pos..pos + self.bytes_per_char];
+    }
+}
+
+#[derive(Clone, Copy)]
+pub struct Size {
+    pub width: usize,
+    pub height: usize,
+}
+
+impl Size {
+    pub const fn new(width: usize, height: usize) -> Self {
+        Self { width, height }
+    }
+}
+
+#[derive(Clone, Copy)]
+pub struct RawBitMap<'a> {
+    pub data: &'a [u8],
+    pub size: Size,
+}
+
+#[allow(dead_code)]
+impl RawBitMap<'_> {
+    pub const fn new(data: &'static [u8], width: usize) -> Self {
+        let size = Size {
+            width: 128,
+            height: data.len() / width / 8,
+        };
+        Self { data, size }
+    }
+
+    pub const fn size(&self) -> Size {
+        self.size
+    }
+
+    pub const fn len(&self) -> usize {
+        self.data.len()
+    }
+}

+ 25 - 0
kernel/src/libs/lib_ui/font/spleen_font.rs

@@ -0,0 +1,25 @@
+use crate::libs::lib_ui::textui::GlyphMapping;
+
+use super::{BitmapFont, RawBitMap, Size};
+
+struct Mapping;
+
+impl GlyphMapping for Mapping {
+    #[inline(always)]
+    fn index(&self, c: char) -> usize {
+        let c = c as usize;
+        match c {
+            0..=255 => c,
+            _ => '?' as usize - ' ' as usize,
+        }
+    }
+}
+
+const SPLEEN_GLYPH_MAPPING: Mapping = Mapping;
+
+#[allow(non_upper_case_globals)]
+pub const SPLEEN_FONT_8x16: BitmapFont<'static> = BitmapFont::new(
+    RawBitMap::new(include_bytes!("binaries/spleen-8x16.raw_bytes"), 128),
+    &SPLEEN_GLYPH_MAPPING,
+    Size::new(8, 16),
+);

+ 4 - 0
kernel/src/libs/lib_ui/mod.rs

@@ -0,0 +1,4 @@
+pub mod font;
+pub mod screen_manager;
+pub mod textui;
+pub mod textui_no_alloc;

+ 58 - 0
kernel/src/libs/lib_ui/screen_manager.h

@@ -0,0 +1,58 @@
+#pragma once
+#include <common/sys/types.h>
+#include <common/glib.h>
+
+// 帧缓冲区标志位
+#define SCM_BF_FB (1 << 0)    // 当前buffer是设备显存中的帧缓冲区
+#define SCM_BF_DB (1 << 1)    // 当前buffer是双缓冲
+#define SCM_BF_TEXT (1 << 2)  // 使用文本模式
+#define SCM_BF_PIXEL (1 << 3) // 使用图像模式
+
+// ui框架类型
+#define SCM_FRAMWORK_TYPE_TEXT (uint8_t)0
+#define SCM_FRAMWORK_TYPE_GUI (uint8_t)1
+
+/**
+ * @brief 帧缓冲区信息结构体
+ *
+ */
+struct scm_buffer_info_t
+{
+    uint32_t width;     // 帧缓冲区宽度(pixel或columns)
+    uint32_t height;    // 帧缓冲区高度(pixel或lines)
+    uint32_t size;      // 帧缓冲区大小(bytes)
+    uint32_t bit_depth; // 像素点位深度
+
+    uint64_t vaddr; // 帧缓冲区的地址
+    uint64_t flags; // 帧缓冲区标志位
+};
+
+/**
+ * @brief 初始化屏幕管理模块
+ *
+ */
+extern void scm_init();
+
+/**
+ * @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题
+ *
+ */
+extern void scm_reinit();
+
+/**
+ * @brief 允许双缓冲区
+ *
+ * @return int
+ */
+extern int scm_enable_double_buffer();
+
+/**
+ * @brief 允许往窗口打印信息
+ *
+ */
+extern void scm_enable_put_to_window();
+/**
+ * @brief 禁止往窗口打印信息
+ *
+ */
+extern void scm_disable_put_to_window();

+ 475 - 0
kernel/src/libs/lib_ui/screen_manager.rs

@@ -0,0 +1,475 @@
+use core::{
+    fmt::Debug,
+    intrinsics::unlikely,
+    sync::atomic::{AtomicBool, AtomicU32, Ordering},
+};
+
+use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc};
+
+use crate::{
+    driver::uart::uart::{c_uart_send_str, UartPort},
+    include::bindings::bindings::{
+        scm_buffer_info_t, video_frame_buffer_info, video_reinitialize, video_set_refresh_target,
+    },
+    libs::{rwlock::RwLock, spinlock::SpinLock},
+    mm::VirtAddr,
+    syscall::SystemError,
+};
+
+use lazy_static::lazy_static;
+
+use super::textui_no_alloc::textui_init_no_alloc;
+
+lazy_static! {
+    /// 全局的UI框架列表
+    pub static ref SCM_FRAMEWORK_LIST: SpinLock<LinkedList<Arc<dyn ScmUiFramework>>> =
+        SpinLock::new(LinkedList::new());
+    /// 当前在使用的UI框架
+    pub static ref CURRENT_FRAMEWORK: RwLock<Option<Arc<dyn ScmUiFramework>>> = RwLock::new(None);
+
+}
+
+/// 是否启用双缓冲
+pub static SCM_DOUBLE_BUFFER_ENABLED: AtomicBool = AtomicBool::new(false);
+
+bitflags! {
+  pub struct ScmBufferFlag:u8 {
+    // 帧缓冲区标志位
+       const SCM_BF_FB = 1 << 0; // 当前buffer是设备显存中的帧缓冲区
+       const SCM_BF_DB = 1 << 1; // 当前buffer是双缓冲
+       const SCM_BF_TEXT = 1 << 2; // 使用文本模式
+       const SCM_BF_PIXEL = 1 << 3; // 使用图像模式
+   }
+}
+#[derive(Clone, Debug)]
+#[allow(dead_code)]
+pub enum ScmFramworkType {
+    Text,
+    Gui,
+    Unused,
+}
+#[derive(Debug)]
+pub enum ScmBuffer {
+    DeviceBuffer(Option<VirtAddr>),
+    DoubleBuffer(Option<Box<[u32]>>),
+}
+#[derive(Debug)]
+pub struct ScmBufferInfo {
+    width: u32,     // 帧缓冲区宽度(pixel或columns)
+    height: u32,    // 帧缓冲区高度(pixel或lines)
+    size: u32,      // 帧缓冲区大小(bytes)
+    bit_depth: u32, // 像素点位深度
+    pub buf: ScmBuffer,
+    flags: ScmBufferFlag, // 帧缓冲区标志位
+}
+impl Clone for ScmBufferInfo {
+    fn clone(&self) -> Self {
+        match self.buf {
+            ScmBuffer::DeviceBuffer(_) => ScmBufferInfo {
+                width: self.width,
+                height: self.height,
+                size: self.size,
+                bit_depth: self.bit_depth,
+                flags: self.flags,
+                buf: ScmBuffer::DeviceBuffer(Option::None),
+            },
+            ScmBuffer::DoubleBuffer(_) => ScmBufferInfo {
+                width: self.width,
+                height: self.height,
+                size: self.size,
+                bit_depth: self.bit_depth,
+                flags: self.flags,
+                buf: ScmBuffer::DoubleBuffer(Option::None),
+            },
+        }
+    }
+}
+
+impl ScmBufferInfo {
+    /// 创建新的帧缓冲区信息
+    ///
+    /// ## 参数
+    ///
+    /// - `buf_type` 帧缓冲区类型
+    ///
+    /// ## 返回值
+    ///
+    /// - `Result<Self, SystemError>` 创建成功返回新的帧缓冲区结构体,创建失败返回错误码
+    pub fn new(buf_type: ScmBufferFlag) -> Result<Self, SystemError> {
+        if unlikely(SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) == false) {
+            let buf_info = ScmBufferInfo::from(unsafe { &video_frame_buffer_info });
+
+            return Ok(buf_info);
+        } else {
+            // 创建双缓冲区
+            let mut frame_buffer_info: ScmBufferInfo =
+                ScmBufferInfo::from(unsafe { &video_frame_buffer_info });
+
+            frame_buffer_info.flags = buf_type;
+            // 这里还是改成使用box来存储数组,如果直接用vec存储,在multiboot2_iter那里会报错,不知为何
+            frame_buffer_info.buf = ScmBuffer::DoubleBuffer(Some(
+                Box::new(vec![
+                    0;
+                    unsafe { (video_frame_buffer_info.size / 4) as usize }
+                ])
+                .into_boxed_slice(),
+            ));
+
+            return Ok(frame_buffer_info);
+        }
+    }
+
+    // 重构了video后可以删除
+    fn vaddr(&mut self) -> VirtAddr {
+        match &self.buf {
+            ScmBuffer::DeviceBuffer(vaddr) => {
+                if !vaddr.is_none() {
+                    vaddr.unwrap()
+                } else {
+                    return VirtAddr::new(0);
+                }
+            }
+            ScmBuffer::DoubleBuffer(buf) => {
+                if !buf.is_none() {
+                    let address = self.buf().as_ptr();
+                    VirtAddr::new(address as usize)
+                } else {
+                    return VirtAddr::new(0);
+                }
+            }
+        }
+    }
+
+    fn buf(&mut self) -> &mut [u32] {
+        let len = self.buf_size() / 4;
+        match &mut self.buf {
+            ScmBuffer::DoubleBuffer(buf) => match buf.as_mut() {
+                Some(buf) => buf,
+                None => panic!("Buffer is none"),
+            },
+            ScmBuffer::DeviceBuffer(vaddr) => match vaddr.as_mut() {
+                Some(vaddr) => {
+                    let buf: &mut [u32] = unsafe {
+                        core::slice::from_raw_parts_mut(vaddr.data() as *mut u32, len as usize)
+                    };
+                    return buf;
+                }
+                None => panic!("Buffer is none"),
+            },
+        }
+    }
+    pub fn buf_size(&self) -> u32 {
+        self.size
+    }
+    pub fn buf_height(&self) -> u32 {
+        self.height
+    }
+    pub fn buf_width(&self) -> u32 {
+        self.width
+    }
+    pub fn is_double_buffer(&self) -> bool {
+        match &self.buf {
+            ScmBuffer::DoubleBuffer(_) => true,
+            _ => false,
+        }
+    }
+    pub fn is_device_buffer(&self) -> bool {
+        match &self.buf {
+            ScmBuffer::DeviceBuffer(_) => true,
+            _ => false,
+        }
+    }
+}
+
+// 重构了video后可以删除
+impl From<&scm_buffer_info_t> for ScmBufferInfo {
+    fn from(value: &scm_buffer_info_t) -> Self {
+        Self {
+            width: value.width,
+            height: value.height,
+            size: value.size,
+            bit_depth: value.bit_depth,
+            buf: ScmBuffer::DeviceBuffer(Some(VirtAddr::new(value.vaddr as usize))),
+            flags: ScmBufferFlag::from_bits_truncate(value.flags as u8),
+        }
+    }
+}
+impl Into<scm_buffer_info_t> for ScmBufferInfo {
+    fn into(mut self) -> scm_buffer_info_t {
+        let vaddr = self.vaddr();
+        scm_buffer_info_t {
+            width: self.width,
+            height: self.height,
+            size: self.size,
+            bit_depth: self.bit_depth,
+            vaddr: vaddr.data() as u64,
+            flags: self.flags.bits as u64,
+        }
+    }
+}
+#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
+pub struct ScmUiFrameworkId(u32);
+
+impl ScmUiFrameworkId {
+    /// 分配一个新的框架id
+    pub fn new() -> Self {
+        static MAX_ID: AtomicU32 = AtomicU32::new(0);
+        return ScmUiFrameworkId(MAX_ID.fetch_add(1, Ordering::SeqCst));
+    }
+}
+#[allow(dead_code)]
+#[derive(Debug, Clone)]
+pub struct ScmUiFrameworkMetadata {
+    id: ScmUiFrameworkId,
+    name: String,
+    framework_type: ScmFramworkType,
+    pub buf_info: ScmBufferInfo,
+}
+
+impl ScmUiFrameworkMetadata {
+    pub fn new(name: String, framework_type: ScmFramworkType) -> Self {
+        match framework_type {
+            ScmFramworkType::Text => {
+                let result = ScmUiFrameworkMetadata {
+                    id: ScmUiFrameworkId::new(),
+                    name,
+                    framework_type: ScmFramworkType::Text,
+                    buf_info: ScmBufferInfo::new(ScmBufferFlag::SCM_BF_TEXT).unwrap(),
+                };
+
+                return result;
+            }
+            ScmFramworkType::Gui => todo!(),
+            ScmFramworkType::Unused => todo!(),
+        }
+    }
+    pub fn buf_info(&self) -> ScmBufferInfo {
+        return self.buf_info.clone();
+    }
+    pub fn set_buf_info(&mut self, buf_info: ScmBufferInfo) {
+        self.buf_info = buf_info;
+    }
+    pub fn buf_is_none(&self) -> bool {
+        match &self.buf_info.buf {
+            ScmBuffer::DeviceBuffer(vaddr) => {
+                return vaddr.is_none();
+            }
+            ScmBuffer::DoubleBuffer(buf) => {
+                return buf.is_none();
+            }
+        }
+    }
+    pub fn buf(&mut self) -> &mut [u32] {
+        if self.buf_is_none() {
+            panic!("buf is none");
+        }
+        self.buf_info.buf()
+    }
+}
+pub trait ScmUiFramework: Sync + Send + Debug {
+    // 安装ui框架的回调函数
+    fn install(&self) -> Result<i32, SystemError> {
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+    // 卸载ui框架的回调函数
+    fn uninstall(&self) -> Result<i32, SystemError> {
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+    // 启用ui框架的回调函数
+    fn enable(&self) -> Result<i32, SystemError> {
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+    // 禁用ui框架的回调函数
+    fn disable(&self) -> Result<i32, SystemError> {
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+    // 改变ui框架的帧缓冲区的回调函数
+    fn change(&self, _buf: ScmBufferInfo) -> Result<i32, SystemError> {
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+    /// @brief 获取ScmUiFramework的元数据
+    /// @return 成功:Ok(ScmUiFramework的元数据)
+    ///         失败:Err(错误码)
+    fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
+        // 若文件系统没有实现此方法,则返回“不支持”
+        return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
+    }
+}
+
+/// 初始化屏幕控制模块
+///
+/// ## 调用时机
+///
+/// 该函数在内核启动的早期进行调用。调用时,内存管理模块尚未初始化。
+#[no_mangle]
+pub extern "C" fn scm_init() {
+    SCM_DOUBLE_BUFFER_ENABLED.store(false, Ordering::SeqCst); // 禁用双缓冲
+
+    textui_init_no_alloc();
+
+    c_uart_send_str(UartPort::COM1.to_u16(), "\nfinish_scm_init\n\0".as_ptr());
+}
+
+/// 启用某个ui框架,将它的帧缓冲区渲染到屏幕上
+/// ## 参数
+///
+/// - framework 要启动的ui框架
+
+pub fn scm_framework_enable(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> {
+    // 获取信息
+    let metadata = framework.metadata()?;
+
+    // if metadata.buf_info.buf.is_null() {
+    //     return Err(SystemError::EINVAL);
+    // }
+    let mut current_framework = CURRENT_FRAMEWORK.write();
+
+    if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) == true {
+        let buf: scm_buffer_info_t = metadata.buf_info.into();
+        let retval = unsafe { video_set_refresh_target(buf) };
+        if retval == 0 {
+            framework.enable()?;
+        }
+    } else {
+        framework.enable()?;
+    }
+
+    current_framework.replace(framework);
+
+    return Ok(0);
+}
+/// 向屏幕管理器注册UI框架
+///
+/// ## 参数
+/// - framework 框架结构体
+
+pub fn scm_register(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> {
+    // 把ui框架加入链表
+
+    SCM_FRAMEWORK_LIST.lock().push_back(framework.clone());
+    // 调用ui框架的回调函数以安装ui框架,并将其激活
+    framework.install()?;
+
+    // 如果当前还没有框架获得了屏幕的控制权,就让其拿去
+    if CURRENT_FRAMEWORK.read().is_none() {
+        return scm_framework_enable(framework);
+    }
+    return Ok(0);
+}
+
+/// 允许双缓冲区
+#[no_mangle]
+pub extern "C" fn scm_enable_double_buffer() -> i32 {
+    let r = true_scm_enable_double_buffer().unwrap_or_else(|e| e.to_posix_errno());
+    if r.is_negative() {
+        c_uart_send_str(
+            UartPort::COM1.to_u16(),
+            "scm enable double buffer fail.\n\0".as_ptr(),
+        );
+    }
+
+    return r;
+}
+fn true_scm_enable_double_buffer() -> Result<i32, SystemError> {
+    if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) {
+        // 已经开启了双缓冲区了, 直接退出
+        return Ok(0);
+    }
+    let scm_list = SCM_FRAMEWORK_LIST.lock();
+    if scm_list.is_empty() {
+        // scm 框架链表为空
+        return Ok(0);
+    }
+    drop(scm_list);
+    SCM_DOUBLE_BUFFER_ENABLED.store(true, Ordering::SeqCst);
+    // 创建双缓冲区
+    let mut buf_info = ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?;
+    let mut refresh_target_buf: scm_buffer_info_t = buf_info.clone().into();
+    // 重构video后进行修改
+    refresh_target_buf.vaddr = buf_info.vaddr().data() as u64;
+    CURRENT_FRAMEWORK
+        .write()
+        .as_ref()
+        .unwrap()
+        .change(buf_info)?;
+    // 设置定时刷新的对象
+    unsafe { video_set_refresh_target(refresh_target_buf) };
+    // 遍历当前所有使用帧缓冲区的框架,更新为双缓冲区
+    for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() {
+        if !(*framework).metadata()?.buf_info.is_double_buffer() {
+            let new_buf_info =
+                ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?;
+            (*framework).change(new_buf_info)?;
+        }
+    }
+    // 通知显示驱动,启动双缓冲
+    unsafe { video_reinitialize(true) };
+
+    return Ok(0);
+}
+/// 允许往窗口打印信息
+#[no_mangle]
+pub fn scm_enable_put_to_window() {
+    // mm之前要继续往窗口打印信息时,因为没有动态内存分配(rwlock与otion依然能用,但是textui并没有往scm注册),且使用的是textui,要直接修改textui里面的值
+    if CURRENT_FRAMEWORK.read().is_none() {
+        super::textui::ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst);
+    } else {
+        let r = CURRENT_FRAMEWORK
+            .write()
+            .as_ref()
+            .unwrap()
+            .enable()
+            .unwrap_or_else(|e| e.to_posix_errno());
+        if r.is_negative() {
+            c_uart_send_str(
+                UartPort::COM1.to_u16(),
+                "scm_enable_put_to_window() failed.\n\0".as_ptr(),
+            );
+        }
+    }
+}
+/// 禁止往窗口打印信息
+#[no_mangle]
+pub fn scm_disable_put_to_window() {
+    // mm之前要停止往窗口打印信息时,因为没有动态内存分配(rwlock与otion依然能用,但是textui并没有往scm注册),且使用的是textui,要直接修改textui里面的值
+    if CURRENT_FRAMEWORK.read().is_none() {
+        super::textui::ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst);
+        assert!(super::textui::ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst) == false);
+    } else {
+        let r = CURRENT_FRAMEWORK
+            .write()
+            .as_ref()
+            .unwrap()
+            .disable()
+            .unwrap_or_else(|e| e.to_posix_errno());
+        if r.is_negative() {
+            c_uart_send_str(
+                UartPort::COM1.to_u16(),
+                "scm_disable_put_to_window() failed.\n\0".as_ptr(),
+            );
+        }
+    }
+}
+/// 当内存管理单元被初始化之后,重新处理帧缓冲区问题
+#[no_mangle]
+pub extern "C" fn scm_reinit() -> i32 {
+    let r = true_scm_reinit().unwrap_or_else(|e| e.to_posix_errno());
+    if r.is_negative() {
+        c_uart_send_str(UartPort::COM1.to_u16(), "scm reinit failed.\n\0".as_ptr());
+    }
+    return r;
+}
+fn true_scm_reinit() -> Result<i32, SystemError> {
+    unsafe { video_reinitialize(false) };
+
+    // 遍历当前所有使用帧缓冲区的框架,更新地址
+    for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() {
+        if framework.metadata()?.buf_info().is_device_buffer() {
+            framework.change(unsafe { ScmBufferInfo::from(&video_frame_buffer_info) })?;
+        }
+    }
+
+    scm_enable_put_to_window();
+
+    return Ok(0);
+}

+ 19 - 0
kernel/src/libs/lib_ui/textui.h

@@ -0,0 +1,19 @@
+#pragma once
+#include <common/glib.h>
+
+/**
+ * @brief 在默认窗口上输出一个字符
+ *
+ * @param character 字符
+ * @param FRcolor 前景色(RGB)
+ * @param BKcolor 背景色(RGB)
+ * @return int
+ */
+extern int rs_textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor);
+
+/**
+ * @brief 初始化text ui框架
+ *
+ * @return int
+ */
+extern int textui_init();

+ 967 - 0
kernel/src/libs/lib_ui/textui.rs

@@ -0,0 +1,967 @@
+use crate::{
+    driver::uart::uart::{c_uart_send, c_uart_send_str, UartPort},
+    include::bindings::bindings::video_frame_buffer_info,
+    kinfo,
+    libs::{lib_ui::font::FONT_8x16, spinlock::SpinLock},
+    syscall::SystemError,
+};
+use alloc::{boxed::Box, collections::LinkedList, string::ToString};
+use alloc::{sync::Arc, vec::Vec};
+use core::{
+    fmt::Debug,
+    intrinsics::unlikely,
+    ops::{Add, AddAssign, Sub},
+    sync::atomic::{AtomicBool, AtomicI32, AtomicU32, Ordering},
+};
+
+use super::{
+    screen_manager::{
+        scm_register, ScmBufferInfo, ScmFramworkType, ScmUiFramework, ScmUiFrameworkMetadata,
+    },
+    textui_no_alloc::no_init_textui_putchar_window,
+};
+
+/// 声明全局的TEXTUI_FRAMEWORK
+static mut __TEXTUI_FRAMEWORK: Option<Box<TextUiFramework>> = None;
+
+/// 每个字符的宽度和高度(像素)
+pub const TEXTUI_CHAR_WIDTH: u32 = 8;
+
+pub const TEXTUI_CHAR_HEIGHT: u32 = 16;
+
+pub static mut TEXTUI_IS_INIT: bool = false;
+
+pub static ENABLE_PUT_TO_WINDOW: AtomicBool = AtomicBool::new(true);
+
+/// 获取TEXTUI_FRAMEWORK的可变实例
+pub fn textui_framework() -> &'static mut TextUiFramework {
+    return unsafe { __TEXTUI_FRAMEWORK.as_mut().unwrap() };
+}
+/// 初始化TEXTUI_FRAMEWORK
+pub unsafe fn textui_framwork_init() {
+    if __TEXTUI_FRAMEWORK.is_none() {
+        kinfo!("textuiframework init");
+        let metadata = ScmUiFrameworkMetadata::new("TextUI".to_string(), ScmFramworkType::Text);
+        // 为textui框架生成第一个窗口
+        let vlines_num = (metadata.buf_info().buf_height() / TEXTUI_CHAR_HEIGHT) as usize;
+
+        let chars_num = (metadata.buf_info().buf_width() / TEXTUI_CHAR_WIDTH) as usize;
+
+        let initial_window = TextuiWindow::new(
+            WindowFlag::TEXTUI_CHROMATIC,
+            vlines_num as i32,
+            chars_num as i32,
+        );
+
+        let current_window: Arc<SpinLock<TextuiWindow>> = Arc::new(SpinLock::new(initial_window));
+
+        let default_window = current_window.clone();
+
+        // 生成窗口链表,并把上面窗口添加进textui框架的窗口链表中
+        let window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>> =
+            Arc::new(SpinLock::new(LinkedList::new()));
+        window_list.lock().push_back(current_window.clone());
+
+        __TEXTUI_FRAMEWORK = Some(Box::new(TextUiFramework::new(
+            metadata,
+            window_list,
+            current_window,
+            default_window,
+        )));
+    } else {
+        panic!("Try to init TEXTUI_FRAMEWORK twice!");
+    }
+}
+// window标志位
+bitflags! {
+    pub struct WindowFlag: u8 {
+        // 采用彩色字符
+        const TEXTUI_CHROMATIC = 1 << 0;
+    }
+}
+
+/**
+ * @brief 黑白字符对象
+ *
+ */
+#[derive(Clone, Debug)]
+struct TextuiCharNormal {
+    _data: u8,
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
+pub struct LineId(i32);
+impl LineId {
+    pub fn new(num: i32) -> Self {
+        LineId(num)
+    }
+
+    pub fn check(&self, max: i32) -> bool {
+        self.0 < max && self.0 >= 0
+    }
+
+    pub fn data(&self) -> i32 {
+        self.0
+    }
+}
+impl Add<i32> for LineId {
+    type Output = LineId;
+    fn add(self, rhs: i32) -> Self::Output {
+        LineId::new(self.0 + rhs)
+    }
+}
+impl Sub<i32> for LineId {
+    type Output = LineId;
+
+    fn sub(self, rhs: i32) -> Self::Output {
+        LineId::new(self.0 - rhs)
+    }
+}
+
+impl Into<i32> for LineId {
+    fn into(self) -> i32 {
+        self.0.clone()
+    }
+}
+impl Into<u32> for LineId {
+    fn into(self) -> u32 {
+        self.0.clone() as u32
+    }
+}
+impl Into<usize> for LineId {
+    fn into(self) -> usize {
+        self.0.clone() as usize
+    }
+}
+impl Sub<LineId> for LineId {
+    type Output = LineId;
+
+    fn sub(mut self, rhs: LineId) -> Self::Output {
+        self.0 -= rhs.0;
+        return self;
+    }
+}
+impl AddAssign<LineId> for LineId {
+    fn add_assign(&mut self, rhs: LineId) {
+        self.0 += rhs.0;
+    }
+}
+#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
+pub struct LineIndex(i32);
+impl LineIndex {
+    pub fn new(num: i32) -> Self {
+        LineIndex(num)
+    }
+    pub fn check(&self, chars_per_line: i32) -> bool {
+        self.0 < chars_per_line && self.0 >= 0
+    }
+}
+impl Add<LineIndex> for LineIndex {
+    type Output = LineIndex;
+
+    fn add(self, rhs: LineIndex) -> Self::Output {
+        LineIndex::new(self.0 + rhs.0)
+    }
+}
+impl Add<i32> for LineIndex {
+    // type Output = Self;
+    type Output = LineIndex;
+
+    fn add(self, rhs: i32) -> Self::Output {
+        LineIndex::new(self.0 + rhs)
+    }
+}
+impl Sub<i32> for LineIndex {
+    type Output = LineIndex;
+
+    fn sub(self, rhs: i32) -> Self::Output {
+        LineIndex::new(self.0 - rhs)
+    }
+}
+
+impl Into<i32> for LineIndex {
+    fn into(self) -> i32 {
+        self.0.clone()
+    }
+}
+impl Into<u32> for LineIndex {
+    fn into(self) -> u32 {
+        self.0.clone() as u32
+    }
+}
+impl Into<usize> for LineIndex {
+    fn into(self) -> usize {
+        self.0.clone() as usize
+    }
+}
+#[derive(Copy, Clone, Debug)]
+pub struct FontColor(u32);
+#[allow(dead_code)]
+impl FontColor {
+    pub const BLUE: FontColor = FontColor::new(0, 0, 0xff);
+    pub const RED: FontColor = FontColor::new(0xff, 0, 0);
+    pub const GREEN: FontColor = FontColor::new(0, 0xff, 0);
+    pub const WHITE: FontColor = FontColor::new(0xff, 0xff, 0xff);
+    pub const BLACK: FontColor = FontColor::new(0, 0, 0);
+    pub const YELLOW: FontColor = FontColor::new(0xff, 0xff, 0);
+    pub const ORANGE: FontColor = FontColor::new(0xff, 0x80, 0);
+    pub const INDIGO: FontColor = FontColor::new(0x00, 0xff, 0xff);
+    pub const PURPLE: FontColor = FontColor::new(0x80, 0x00, 0xff);
+
+    pub const fn new(r: u8, g: u8, b: u8) -> Self {
+        let val = ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
+        return FontColor(val & 0x00ffffff);
+    }
+}
+
+impl From<u32> for FontColor {
+    fn from(value: u32) -> Self {
+        return Self(value & 0x00ffffff);
+    }
+}
+impl Into<usize> for FontColor {
+    fn into(self) -> usize {
+        self.0.clone() as usize
+    }
+}
+impl Into<u32> for FontColor {
+    fn into(self) -> u32 {
+        self.0.clone()
+    }
+}
+impl Into<u16> for FontColor {
+    fn into(self) -> u16 {
+        self.0.clone() as u16
+    }
+}
+impl Into<u64> for FontColor {
+    fn into(self) -> u64 {
+        self.0.clone() as u64
+    }
+}
+
+/// 彩色字符对象
+
+#[derive(Clone, Debug, Copy)]
+pub struct TextuiCharChromatic {
+    c: Option<char>,
+
+    // 前景色
+    frcolor: FontColor, // rgb
+
+    // 背景色
+    bkcolor: FontColor, // rgb
+}
+
+#[derive(Debug)]
+pub struct TextuiBuf<'a>(&'a mut [u32]);
+
+impl TextuiBuf<'_> {
+    pub fn new(buf: &mut [u32]) -> TextuiBuf {
+        TextuiBuf(buf)
+    }
+    pub fn put_color_in_pixel(&mut self, color: u32, index: usize) {
+        let buf: &mut [u32] = self.0;
+        buf[index] = color;
+    }
+    pub fn get_index_of_next_line(now_index: usize) -> usize {
+        textui_framework().metadata.buf_info().buf_width() as usize + now_index
+    }
+    pub fn get_index_by_x_y(x: usize, y: usize) -> usize {
+        textui_framework().metadata.buf_info().buf_width() as usize * y + x
+    }
+    pub fn get_start_index_by_lineid_lineindex(lineid: LineId, lineindex: LineIndex) -> usize {
+        //   x 左上角列像素点位置
+        //   y 左上角行像素点位置
+        let index_x: u32 = lineindex.into();
+        let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
+
+        let id_y: u32 = lineid.into();
+        let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
+
+        TextuiBuf::get_index_by_x_y(x as usize, y as usize)
+    }
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
+pub struct Font([u8; 16]);
+impl Font {
+    #[inline]
+    pub fn get_font(character: char) -> Font {
+        let x = FONT_8x16.char_map(character);
+
+        let mut data = [0u8; 16];
+        data.copy_from_slice(x);
+        return Font(data);
+    }
+    pub fn is_frcolor(&self, height: usize, width: usize) -> bool {
+        let w = self.0[height];
+        let testbit = 1 << (8 - width);
+        w & testbit != 0
+    }
+}
+
+impl TextuiCharChromatic {
+    pub fn new(c: Option<char>, frcolor: FontColor, bkcolor: FontColor) -> Self {
+        TextuiCharChromatic {
+            c,
+            frcolor,
+            bkcolor,
+        }
+    }
+
+    /// 将该字符对象输出到缓冲区
+    /// ## 参数
+    /// -line_id 要放入的真实行号
+    /// -index 要放入的真实列号
+    pub fn textui_refresh_character(
+        &self,
+        lineid: LineId,
+        lineindex: LineIndex,
+    ) -> Result<i32, SystemError> {
+        // 找到要渲染的字符的像素点数据
+
+        let font: Font = Font::get_font(self.c.unwrap_or(' '));
+
+        let mut count = TextuiBuf::get_start_index_by_lineid_lineindex(lineid, lineindex);
+
+        let mut buf = TextuiBuf::new(textui_framework().metadata.buf());
+        // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
+        for i in 0..TEXTUI_CHAR_HEIGHT {
+            let start = count;
+            for j in 0..TEXTUI_CHAR_WIDTH {
+                if font.is_frcolor(i as usize, j as usize) {
+                    // 字,显示前景色
+                    buf.put_color_in_pixel(self.frcolor.into(), count);
+                } else {
+                    // 背景色
+                    buf.put_color_in_pixel(self.bkcolor.into(), count);
+                }
+                count += 1;
+            }
+            count = TextuiBuf::get_index_of_next_line(start);
+        }
+
+        return Ok(0);
+    }
+
+    pub fn no_init_textui_render_chromatic(&self, lineid: LineId, lineindex: LineIndex) {
+        // 找到要渲染的字符的像素点数据
+        let font = Font::get_font(self.c.unwrap_or(' '));
+
+        //   x 左上角列像素点位置
+        //   y 左上角行像素点位置
+        let index_x: u32 = lineindex.into();
+        let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
+
+        let id_y: u32 = lineid.into();
+        let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
+        // 找到输入缓冲区的起始地址位置
+        let fb = unsafe { video_frame_buffer_info.vaddr };
+
+        let mut testbit: u32; // 用来测试特定行的某列是背景还是字体本身
+
+        // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
+        for i in 0..TEXTUI_CHAR_HEIGHT {
+            // 计算出帧缓冲区每一行打印的起始位置的地址(起始位置+(y+i)*缓冲区的宽度+x)
+
+            let mut addr: *mut u32 = (fb
+                + unsafe { video_frame_buffer_info.width } as u64 * 4 * (y as u64 + i as u64)
+                + 4 * x as u64) as *mut u32;
+
+            testbit = 1 << (TEXTUI_CHAR_WIDTH + 1);
+
+            for _j in 0..TEXTUI_CHAR_WIDTH {
+                //从左往右逐个测试相应位
+                testbit >>= 1;
+                if (font.0[i as usize] & testbit as u8) != 0 {
+                    unsafe { *addr = self.frcolor.into() }; // 字,显示前景色
+                } else {
+                    unsafe { *addr = self.bkcolor.into() }; // 背景色
+                }
+
+                unsafe {
+                    addr = (addr.offset(1)) as *mut u32;
+                }
+            }
+        }
+    }
+}
+
+/// 单色显示的虚拟行结构体
+
+#[derive(Clone, Debug, Default)]
+pub struct TextuiVlineNormal {
+    _characters: Vec<TextuiCharNormal>, // 字符对象数组
+    _index: i16,                        // 当前操作的位置
+}
+/// 彩色显示的虚拟行结构体
+
+#[derive(Clone, Debug, Default)]
+pub struct TextuiVlineChromatic {
+    chars: Vec<TextuiCharChromatic>, // 字符对象数组
+    index: LineIndex,                // 当前操作的位置
+}
+impl TextuiVlineChromatic {
+    pub fn new(char_num: usize) -> Self {
+        let mut r = TextuiVlineChromatic {
+            chars: Vec::with_capacity(char_num),
+            index: LineIndex::new(0),
+        };
+
+        for _ in 0..char_num {
+            r.chars.push(TextuiCharChromatic::new(
+                None,
+                FontColor::BLACK,
+                FontColor::BLACK,
+            ));
+        }
+
+        return r;
+    }
+}
+
+#[derive(Clone, Debug)]
+pub enum TextuiVline {
+    Chromatic(TextuiVlineChromatic),
+    _Normal(TextuiVlineNormal),
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
+pub struct WindowId(u32);
+
+impl WindowId {
+    pub fn new() -> Self {
+        static MAX_ID: AtomicU32 = AtomicU32::new(0);
+        return WindowId(MAX_ID.fetch_add(1, Ordering::SeqCst));
+    }
+}
+#[allow(dead_code)]
+#[derive(Clone, Debug)]
+pub struct TextuiWindow {
+    // 虚拟行是个循环表,头和尾相接
+    id: WindowId,
+    // 虚拟行总数
+    vline_sum: i32,
+    // 当前已经使用了的虚拟行总数(即在已经输入到缓冲区(之后显示在屏幕上)的虚拟行数量)
+    vlines_used: i32,
+    // 位于最顶上的那一个虚拟行的行号
+    top_vline: LineId,
+    // 储存虚拟行的数组
+    vlines: Vec<TextuiVline>,
+    // 正在操作的vline
+    vline_operating: LineId,
+    // 每行最大容纳的字符数
+    chars_per_line: i32,
+    // 窗口flag
+    flags: WindowFlag,
+}
+
+impl TextuiWindow {
+    /// 使用参数初始化window对象
+    /// ## 参数
+    ///
+    /// -flags 标志位
+    /// -vlines_num 虚拟行的总数
+    /// -chars_num 每行最大的字符数
+
+    pub fn new(flags: WindowFlag, vlines_num: i32, chars_num: i32) -> Self {
+        let mut initial_vlines = Vec::new();
+
+        for _ in 0..vlines_num {
+            let vline = TextuiVlineChromatic::new(chars_num as usize);
+
+            initial_vlines.push(TextuiVline::Chromatic(vline));
+        }
+        TextuiWindow {
+            id: WindowId::new(),
+            flags,
+            vline_sum: vlines_num,
+            vlines_used: 1,
+            top_vline: LineId::new(0),
+            vlines: initial_vlines,
+            vline_operating: LineId::new(0),
+            chars_per_line: chars_num,
+        }
+    }
+
+    /// 刷新某个窗口的缓冲区的某个虚拟行的连续n个字符对象
+    /// ## 参数
+    /// - window 窗口结构体
+    /// - vline_id 要刷新的虚拟行号
+    /// - start 起始字符号
+    /// - count 要刷新的字符数量
+
+    fn textui_refresh_characters(
+        &mut self,
+        vline_id: LineId,
+        start: LineIndex,
+        count: i32,
+    ) -> Result<(), SystemError> {
+        let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
+
+        // 判断虚拟行参数是否合法
+        if unlikely(
+            !vline_id.check(self.vline_sum)
+                || (<LineIndex as Into<i32>>::into(start) + count) > self.chars_per_line,
+        ) {
+            return Err(SystemError::EINVAL);
+        }
+        // 计算虚拟行对应的真实行(即要渲染的行)
+        let mut actual_line_id = vline_id - self.top_vline; //为正说明虚拟行不在真实行显示的区域上面
+
+        if <LineId as Into<i32>>::into(actual_line_id) < 0 {
+            //真实行数小于虚拟行数,则需要加上真实行数的位置,以便正确计算真实行
+            actual_line_id = actual_line_id + actual_line_sum;
+        }
+
+        // 将此窗口的某个虚拟行的连续n个字符对象往缓存区写入
+        if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
+            let vline = &mut self.vlines[<LineId as Into<usize>>::into(vline_id)];
+            let mut i = 0;
+            let mut index = start;
+
+            while i < count {
+                if let TextuiVline::Chromatic(vline) = vline {
+                    vline.chars[<LineIndex as Into<usize>>::into(index)]
+                        .textui_refresh_character(actual_line_id, index)?;
+
+                    index = index + 1;
+                }
+                i += 1;
+            }
+        }
+
+        return Ok(());
+    }
+
+    /// 重新渲染某个窗口的某个虚拟行
+    /// ## 参数
+
+    /// - window 窗口结构体
+    /// - vline_id 虚拟行号
+
+    fn textui_refresh_vline(&mut self, vline_id: LineId) -> Result<(), SystemError> {
+        if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
+            return self.textui_refresh_characters(
+                vline_id,
+                LineIndex::new(0),
+                self.chars_per_line,
+            );
+        } else {
+            //todo支持纯文本字符()
+            todo!();
+        }
+    }
+
+    // 刷新某个窗口的start 到start + count行(即将这些行输入到缓冲区)
+    fn textui_refresh_vlines(&mut self, start: LineId, count: i32) -> Result<i32, SystemError> {
+        let mut refresh_count = count;
+        for i in <LineId as Into<i32>>::into(start)
+            ..(self.vline_sum).min(<LineId as Into<i32>>::into(start) + count)
+        {
+            self.textui_refresh_vline(LineId::new(i))?;
+            refresh_count -= 1;
+        }
+        //因为虚拟行是循环表
+        let mut refresh_start = 0;
+        while refresh_count > 0 {
+            self.textui_refresh_vline(LineId::new(refresh_start))?;
+            refresh_start += 1;
+            refresh_count -= 1;
+        }
+        return Ok(0);
+    }
+
+    /// 往某个窗口的缓冲区的某个虚拟行插入换行
+    /// ## 参数
+    /// - window 窗口结构体
+    /// - vline_id 虚拟行号
+
+    fn textui_new_line(&mut self) -> Result<i32, SystemError> {
+        // todo: 支持在两个虚拟行之间插入一个新行
+        let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
+        self.vline_operating = self.vline_operating + 1;
+        //如果已经到了最大行数,则重新从0开始
+        if !self.vline_operating.check(self.vline_sum) {
+            self.vline_operating = LineId::new(0);
+        }
+
+        if let TextuiVline::Chromatic(vline) =
+            &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
+        {
+            for i in 0..self.chars_per_line {
+                if let Some(v_char) = vline.chars.get_mut(i as usize) {
+                    v_char.c = None;
+                    v_char.frcolor = FontColor::BLACK;
+                    v_char.bkcolor = FontColor::BLACK;
+                }
+            }
+            vline.index = LineIndex::new(0);
+        }
+        // 当已经使用的虚拟行总数等于真实行总数时,说明窗口中已经显示的文本行数已经达到了窗口的最大容量。这时,如果继续在窗口中添加新的文本,就会导致文本溢出窗口而无法显示。因此,需要往下滚动屏幕来显示更多的文本。
+
+        if self.vlines_used == actual_line_sum {
+            self.top_vline = self.top_vline + 1;
+
+            if !self.top_vline.check(self.vline_sum) {
+                self.top_vline = LineId::new(0);
+            }
+
+            // 刷新所有行
+            self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
+        } else {
+            //换行说明上一行已经在缓冲区中,所以已经使用的虚拟行总数+1
+            self.vlines_used += 1;
+        }
+
+        return Ok(0);
+    }
+
+    /// 真正向窗口的缓冲区上输入字符的函数(位置为window.vline_operating,window.vline_operating.index)
+    /// ## 参数
+    /// - window
+    /// - character
+
+    fn true_textui_putchar_window(
+        &mut self,
+        character: char,
+        frcolor: FontColor,
+        bkcolor: FontColor,
+    ) -> Result<(), SystemError> {
+        // 启用彩色字符
+        if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
+            let mut line_index = LineIndex::new(0); //操作的列号
+            if let TextuiVline::Chromatic(vline) =
+                &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
+            {
+                let index = <LineIndex as Into<usize>>::into(vline.index);
+
+                if let Some(v_char) = vline.chars.get_mut(index) {
+                    v_char.c = Some(character);
+                    v_char.frcolor = frcolor;
+                    v_char.bkcolor = bkcolor;
+                }
+                line_index = vline.index;
+                vline.index = vline.index + 1;
+            }
+
+            self.textui_refresh_characters(self.vline_operating, line_index, 1)?;
+
+            // 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行
+            if !line_index.check(self.chars_per_line - 1) {
+                self.textui_new_line()?;
+            }
+        } else {
+            // todo: 支持纯文本字符
+            todo!();
+        }
+        return Ok(());
+    }
+    /// 根据输入的一个字符在窗口上输出
+    /// ## 参数
+
+    /// - window 窗口
+    /// - character 字符
+    /// - FRcolor 前景色(RGB)
+    /// - BKcolor 背景色(RGB)
+
+    fn textui_putchar_window(
+        &mut self,
+        character: char,
+        frcolor: FontColor,
+        bkcolor: FontColor,
+        is_enable_window: bool,
+    ) -> Result<(), SystemError> {
+        let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
+
+        //字符'\0'代表ASCII码表中的空字符,表示字符串的结尾
+        if unlikely(character == '\0') {
+            return Ok(());
+        }
+
+        if unlikely(character == '\r') {
+            return Ok(());
+        }
+
+        // 暂不支持纯文本窗口
+        if !self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
+            return Ok(());
+        }
+
+        //进行换行操作
+        if character == '\n' {
+            // 换行时还需要输出\r
+            c_uart_send(UartPort::COM1.to_u16(), b'\r');
+            if is_enable_window == true {
+                self.textui_new_line()?;
+            }
+            return Ok(());
+        }
+        // 输出制表符
+        else if character == '\t' {
+            if is_enable_window == true {
+                if let TextuiVline::Chromatic(vline) =
+                    &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
+                {
+                    //打印的空格数(注意将每行分成一个个表格,每个表格为8个字符)
+                    let mut space_to_print = 8 - <LineIndex as Into<usize>>::into(vline.index) % 8;
+                    while space_to_print > 0 {
+                        self.true_textui_putchar_window(' ', frcolor, bkcolor)?;
+                        space_to_print -= 1;
+                    }
+                }
+            }
+        }
+        // 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。
+        else if character == '\x08' {
+            if is_enable_window == true {
+                let mut tmp = LineIndex(0);
+                if let TextuiVline::Chromatic(vline) =
+                    &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
+                {
+                    vline.index = vline.index - 1;
+                    tmp = vline.index;
+                }
+                if <LineIndex as Into<i32>>::into(tmp) >= 0 {
+                    if let TextuiVline::Chromatic(vline) =
+                        &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
+                    {
+                        if let Some(v_char) =
+                            vline.chars.get_mut(<LineIndex as Into<usize>>::into(tmp))
+                        {
+                            v_char.c = Some(' ');
+
+                            v_char.bkcolor = bkcolor;
+                        }
+                    }
+                    return self.textui_refresh_characters(self.vline_operating, tmp, 1);
+                }
+                // 需要向上缩一行
+                if <LineIndex as Into<i32>>::into(tmp) < 0 {
+                    // 当前行为空,需要重新刷新
+                    if let TextuiVline::Chromatic(vline) =
+                        &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
+                    {
+                        vline.index = LineIndex::new(0);
+                        for i in 0..self.chars_per_line {
+                            if let Some(v_char) = vline.chars.get_mut(i as usize) {
+                                v_char.c = None;
+                                v_char.frcolor = FontColor::BLACK;
+                                v_char.bkcolor = FontColor::BLACK;
+                            }
+                        }
+                    }
+                    // 上缩一行
+                    self.vline_operating = self.vline_operating - 1;
+                    if self.vline_operating.data() < 0 {
+                        self.vline_operating = LineId(self.vline_sum - 1);
+                    }
+
+                    // 考虑是否向上滚动(在top_vline上退格)
+                    if self.vlines_used > actual_line_sum {
+                        self.top_vline = self.top_vline - 1;
+                        if <LineId as Into<i32>>::into(self.top_vline) < 0 {
+                            self.top_vline = LineId(self.vline_sum - 1);
+                        }
+                    }
+                    //因为上缩一行所以显示在屏幕中的虚拟行少一
+                    self.vlines_used -= 1;
+                    self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
+                }
+            }
+        } else {
+            // 输出其他字符
+
+            c_uart_send(UartPort::COM1.to_u16(), character as u8);
+
+            if is_enable_window == true {
+                if let TextuiVline::Chromatic(vline) =
+                    &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
+                {
+                    if !vline.index.check(self.chars_per_line) {
+                        self.textui_new_line()?;
+                    }
+
+                    return self.true_textui_putchar_window(character, frcolor, bkcolor);
+                }
+            }
+        }
+
+        return Ok(());
+    }
+}
+impl Default for TextuiWindow {
+    fn default() -> Self {
+        TextuiWindow {
+            id: WindowId(0),
+            flags: WindowFlag::TEXTUI_CHROMATIC,
+            vline_sum: 0,
+            vlines_used: 1,
+            top_vline: LineId::new(0),
+            vlines: Vec::new(),
+            vline_operating: LineId::new(0),
+            chars_per_line: 0,
+        }
+    }
+}
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct TextUiFramework {
+    metadata: ScmUiFrameworkMetadata,
+    window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
+    actual_line: AtomicI32, // 真实行的数量(textui的帧缓冲区能容纳的内容的行数)
+    current_window: Arc<SpinLock<TextuiWindow>>, // 当前的主窗口
+    default_window: Arc<SpinLock<TextuiWindow>>, // 默认print到的窗口
+}
+
+impl TextUiFramework {
+    pub fn new(
+        metadata: ScmUiFrameworkMetadata,
+        window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
+        current_window: Arc<SpinLock<TextuiWindow>>,
+        default_window: Arc<SpinLock<TextuiWindow>>,
+    ) -> Self {
+        let actual_line =
+            AtomicI32::new((&metadata.buf_info().buf_height() / TEXTUI_CHAR_HEIGHT) as i32);
+        let inner = TextUiFramework {
+            metadata,
+            window_list,
+            actual_line,
+            current_window,
+            default_window,
+        };
+        return inner;
+    }
+}
+
+impl ScmUiFramework for &mut TextUiFramework {
+    // 安装ui框架的回调函数
+    fn install(&self) -> Result<i32, SystemError> {
+        c_uart_send_str(
+            UartPort::COM1.to_u16(),
+            "\ntextui_install_handler\n\0".as_ptr(),
+        );
+        return Ok(0);
+    }
+    // 卸载ui框架的回调函数
+    fn uninstall(&self) -> Result<i32, SystemError> {
+        return Ok(0);
+    }
+    // 启用ui框架的回调函数
+    fn enable(&self) -> Result<i32, SystemError> {
+        ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst);
+        return Ok(0);
+    }
+    // 禁用ui框架的回调函数
+    fn disable(&self) -> Result<i32, SystemError> {
+        ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst);
+
+        return Ok(0);
+    }
+    // 改变ui框架的帧缓冲区的回调函数
+    fn change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError> {
+        let src_buf = textui_framework().metadata.buf();
+        textui_framework().metadata.set_buf_info(buf_info);
+        let dst_buf = textui_framework().metadata.buf();
+        dst_buf.copy_from_slice(src_buf);
+        return Ok(0);
+    }
+    ///  获取ScmUiFramework的元数据
+    ///  ## 返回值
+    ///
+    ///  -成功:Ok(ScmUiFramework的元数据)
+    ///  -失败:Err(错误码)
+    fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
+        let metadata = self.metadata.clone();
+
+        return Ok(metadata);
+    }
+}
+
+/// Mapping from characters to glyph indices.
+pub trait GlyphMapping: Sync {
+    /// Maps a character to a glyph index.
+    ///
+    /// If `c` isn't included in the font the index of a suitable replacement glyph is returned.
+    fn index(&self, c: char) -> usize;
+}
+
+impl<F> GlyphMapping for F
+where
+    F: Sync + Fn(char) -> usize,
+{
+    fn index(&self, c: char) -> usize {
+        self(c)
+    }
+}
+
+/// 在默认窗口上输出一个字符
+/// ## 参数
+/// - character 字符
+/// - FRcolor 前景色(RGB)
+/// - BKcolor 背景色(RGB)
+
+#[no_mangle]
+pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 {
+    return textui_putchar(
+        character as char,
+        FontColor::from(fr_color),
+        FontColor::from(bk_color),
+    )
+    .map(|_| 0)
+    .unwrap_or_else(|e| e.to_posix_errno());
+}
+
+pub fn textui_putchar(
+    character: char,
+    fr_color: FontColor,
+    bk_color: FontColor,
+) -> Result<(), SystemError> {
+    if unsafe { TEXTUI_IS_INIT } {
+        return textui_framework()
+            .current_window
+            .lock()
+            .textui_putchar_window(
+                character,
+                fr_color,
+                bk_color,
+                ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst),
+            );
+    } else {
+        //未初始化暴力输出
+        return no_init_textui_putchar_window(
+            character,
+            fr_color,
+            bk_color,
+            ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst),
+        );
+    }
+}
+
+/// 初始化text ui框架
+
+#[no_mangle]
+pub extern "C" fn rs_textui_init() -> i32 {
+    let r = textui_init().unwrap_or_else(|e| e.to_posix_errno());
+    if r.is_negative() {
+        c_uart_send_str(UartPort::COM1.to_u16(), "textui init failed.\n\0".as_ptr());
+    }
+    return r;
+}
+
+fn textui_init() -> Result<i32, SystemError> {
+    unsafe { textui_framwork_init() };
+    let textui_framework = textui_framework();
+
+    unsafe { TEXTUI_IS_INIT = true };
+
+    scm_register(Arc::new(textui_framework))?;
+
+    c_uart_send_str(
+        UartPort::COM1.to_u16(),
+        "\ntext ui initialized\n\0".as_ptr(),
+    );
+
+    return Ok(0);
+}

+ 125 - 0
kernel/src/libs/lib_ui/textui_no_alloc.rs

@@ -0,0 +1,125 @@
+use core::{
+    intrinsics::unlikely,
+    sync::atomic::{AtomicI32, Ordering},
+};
+
+use crate::{
+    driver::uart::uart::{c_uart_send, UartPort},
+    include::bindings::bindings::video_frame_buffer_info,
+    syscall::SystemError,
+};
+
+use super::textui::{
+    FontColor, LineId, LineIndex, TextuiCharChromatic, TEXTUI_CHAR_HEIGHT, TEXTUI_CHAR_WIDTH,
+};
+
+pub static TRUE_LINE_NUM: AtomicI32 = AtomicI32::new(0);
+pub static CHAR_PER_LINE: AtomicI32 = AtomicI32::new(0);
+/// textui 未初始化时直接向缓冲区写,不使用虚拟行
+pub static NO_ALLOC_OPERATIONS_LINE: AtomicI32 = AtomicI32::new(0);
+pub static NO_ALLOC_OPERATIONS_INDEX: AtomicI32 = AtomicI32::new(0);
+
+/// 当系统刚启动的时候,由于内存管理未初始化,而texiui需要动态内存分配。因此只能暂时暴力往屏幕(video_frame_buffer_info)输出信息
+pub fn textui_init_no_alloc() {
+    TRUE_LINE_NUM.store(
+        unsafe { (video_frame_buffer_info.height / TEXTUI_CHAR_HEIGHT) as i32 },
+        Ordering::SeqCst,
+    );
+
+    CHAR_PER_LINE.store(
+        unsafe { (video_frame_buffer_info.width / TEXTUI_CHAR_WIDTH) as i32 },
+        Ordering::SeqCst,
+    );
+}
+
+pub fn no_init_textui_putchar_window(
+    character: char,
+    frcolor: FontColor,
+    bkcolor: FontColor,
+    is_put_to_window: bool,
+) -> Result<(), SystemError> {
+    if NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst) > TRUE_LINE_NUM.load(Ordering::SeqCst) {
+        NO_ALLOC_OPERATIONS_LINE.store(0, Ordering::SeqCst);
+    }
+    //字符'\0'代表ASCII码表中的空字符,表示字符串的结尾
+    if unlikely(character == '\0') {
+        return Ok(());
+    }
+
+    c_uart_send(UartPort::COM1.to_u16(), character as u8);
+
+    // 进行换行操作
+    if unlikely(character == '\n') {
+        // 换行时还需要输出\r
+        c_uart_send(UartPort::COM1.to_u16(), b'\r');
+        if is_put_to_window == true {
+            NO_ALLOC_OPERATIONS_LINE.fetch_add(1, Ordering::SeqCst);
+            NO_ALLOC_OPERATIONS_INDEX.store(0, Ordering::SeqCst);
+        }
+        return Ok(());
+    }
+    // 输出制表符
+    else if character == '\t' {
+        if is_put_to_window == true {
+            let char = TextuiCharChromatic::new(Some(' '), frcolor, bkcolor);
+
+            //打印的空格数(注意将每行分成一个个表格,每个表格为8个字符)
+            let mut space_to_print = 8 - NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst) % 8;
+            while space_to_print > 0 {
+                char.no_init_textui_render_chromatic(
+                    LineId::new(NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst)),
+                    LineIndex::new(NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)),
+                );
+                NO_ALLOC_OPERATIONS_INDEX.fetch_add(1, Ordering::SeqCst);
+                space_to_print -= 1;
+            }
+            return Ok(());
+        }
+    }
+    // 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。
+    else if character == '\x08' {
+        if is_put_to_window == true {
+            NO_ALLOC_OPERATIONS_INDEX.fetch_sub(1, Ordering::SeqCst);
+            let op_char = NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst);
+            if op_char >= 0 {
+                let char = TextuiCharChromatic::new(Some(' '), frcolor, bkcolor);
+                char.no_init_textui_render_chromatic(
+                    LineId::new(NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst)),
+                    LineIndex::new(NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)),
+                );
+
+                NO_ALLOC_OPERATIONS_INDEX.fetch_add(1, Ordering::SeqCst);
+            }
+            // 需要向上缩一行
+            if op_char < 0 {
+                // 上缩一行
+                NO_ALLOC_OPERATIONS_INDEX.store(0, Ordering::SeqCst);
+                NO_ALLOC_OPERATIONS_LINE.fetch_sub(1, Ordering::SeqCst);
+
+                if NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst) < 0 {
+                    NO_ALLOC_OPERATIONS_LINE.store(0, Ordering::SeqCst);
+                }
+            }
+        }
+    } else {
+        if is_put_to_window == true {
+            // 输出其他字符
+            let char = TextuiCharChromatic::new(Some(character), frcolor, bkcolor);
+
+            if NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)
+                == CHAR_PER_LINE.load(Ordering::SeqCst)
+            {
+                NO_ALLOC_OPERATIONS_INDEX.store(0, Ordering::SeqCst);
+                NO_ALLOC_OPERATIONS_LINE.fetch_add(1, Ordering::SeqCst);
+            }
+            char.no_init_textui_render_chromatic(
+                LineId::new(NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst)),
+                LineIndex::new(NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)),
+            );
+
+            NO_ALLOC_OPERATIONS_INDEX.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+
+    return Ok(());
+}

+ 1 - 0
kernel/src/libs/mod.rs

@@ -7,6 +7,7 @@ pub mod ffi_convert;
 pub mod int_like;
 pub mod keyboard_parser;
 pub mod lazy_init;
+pub mod lib_ui;
 pub mod list;
 pub mod lockref;
 pub mod mutex;

+ 2 - 2
kernel/src/libs/printk.c

@@ -5,7 +5,7 @@
 #include <common/printk.h>
 
 #include <common/spinlock.h>
-#include <libs/libUI/textui.h>
+#include <libs/lib_ui/textui.h>
 #include <mm/mm.h>
 
 #include <common/math.h>
@@ -610,7 +610,7 @@ int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ..
     {
         current = *(buf + i);
         // 输出
-        textui_putchar(current, FRcolor, BKcolor);
+        rs_textui_putchar(current, FRcolor, BKcolor);
     }
     io_mfence();
     spin_unlock_irqrestore(&__printk_lock, rflags);

+ 13 - 134
kernel/src/libs/printk.rs

@@ -1,35 +1,6 @@
-#![allow(unused)]
-use crate::{
-    driver::uart::uart::c_uart_send_str,
-    include::bindings::bindings::{printk_color, BLACK, WHITE},
-};
-use ::core::ffi::c_char;
-use alloc::vec::Vec;
-use core::{
-    fmt::{self, Write},
-    intrinsics::{likely, unlikely},
-    sync::atomic::{AtomicBool, Ordering},
-};
-
-// ====== 定义颜色 ======
-/// 白色
-pub const COLOR_WHITE: u32 = 0x00ffffff;
-/// 黑色
-pub const COLOR_BLACK: u32 = 0x00000000;
-/// 红色
-pub const COLOR_RED: u32 = 0x00ff0000;
-/// 橙色
-pub const COLOR_ORANGE: u32 = 0x00ff8000;
-/// 黄色
-pub const COLOR_YELLOW: u32 = 0x00ffff00;
-/// 绿色
-pub const COLOR_GREEN: u32 = 0x0000ff00;
-/// 蓝色
-pub const COLOR_BLUE: u32 = 0x000000ff;
-/// 靛色
-pub const COLOR_INDIGO: u32 = 0x0000ffff;
-/// 紫色
-pub const COLOR_PURPLE: u32 = 0x008000ff;
+use core::fmt::{self, Write};
+
+use super::lib_ui::textui::{textui_putchar, FontColor};
 
 #[macro_export]
 macro_rules! print {
@@ -74,7 +45,7 @@ macro_rules! kinfo {
 #[macro_export]
 macro_rules! kwarn {
     ($($arg:tt)*) => {
-        $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_YELLOW, $crate::libs::printk::COLOR_BLACK, "[ WARN ] ");
+        $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::YELLOW, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ WARN ] ");
         $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
     }
 }
@@ -82,7 +53,7 @@ macro_rules! kwarn {
 #[macro_export]
 macro_rules! kerror {
     ($($arg:tt)*) => {
-        $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_RED, $crate::libs::printk::COLOR_BLACK, "[ ERROR ] ");
+        $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ ERROR ] ");
         $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
     }
 }
@@ -90,121 +61,30 @@ macro_rules! kerror {
 #[macro_export]
 macro_rules! kBUG {
     ($($arg:tt)*) => {
-        $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_RED, $crate::libs::printk::COLOR_BLACK, "[ BUG ] ");
+        $crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ BUG ] ");
         $crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
     }
 }
 
 pub struct PrintkWriter;
 
-/// 由于内存管理初始化完成之前,无法使用动态内存分配,所以需要在内存管理初始化完成之后才能使用动态内存分配
-static ALLOW_ALLOC_ATOMIC: AtomicBool = AtomicBool::new(false);
-static mut ALLOW_ALLOC_BOOL: bool = false;
-
 impl PrintkWriter {
     #[inline]
     pub fn __write_fmt(&mut self, args: fmt::Arguments) {
-        self.write_fmt(args);
+        self.write_fmt(args).ok();
     }
 
-    /// 调用C语言编写的printk_color,并输出白底黑字(暂时只支持ascii字符)
+    /// 并输出白底黑字
     /// @param str: 要写入的字符
     pub fn __write_string(&mut self, s: &str) {
-        if unlikely(!self.allow_alloc()) {
-            self.__write_string_on_stack(s);
-            return;
-        }
-        let str_to_print = self.__utf8_to_ascii(s);
-        unsafe {
-            printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
-        }
-    }
-
-    pub fn __write_string_color(&self, fr_color: u32, bk_color: u32, s: &str) {
-        if unlikely(!self.allow_alloc()) {
-            self.__write_string_on_stack(s);
-            return;
-        }
-
-        let str_to_print = self.__utf8_to_ascii(s);
-        unsafe {
-            printk_color(fr_color, bk_color, str_to_print.as_ptr() as *const c_char);
-        }
-    }
-
-    #[inline]
-    fn allow_alloc(&self) -> bool {
-        // 由于allow_alloc只可能由false变为true
-        // 因此采用两种方式读取它,一种是原子操作,一种是普通的bool,以优化性能。
-        if likely(unsafe { ALLOW_ALLOC_BOOL }) {
-            return true;
-        } else {
-            return ALLOW_ALLOC_ATOMIC.load(Ordering::SeqCst);
+        for c in s.chars() {
+            textui_putchar(c, FontColor::WHITE, FontColor::BLACK).ok();
         }
     }
 
-    /// 允许动态内存分配
-    pub fn enable_alloc(&self) {
-        ALLOW_ALLOC_ATOMIC.store(true, Ordering::SeqCst);
-        unsafe {
-            ALLOW_ALLOC_BOOL = true;
-        }
-    }
-
-    /// 将s这个utf8字符串,转换为ascii字符串
-    /// @param s 待转换的utf8字符串
-    /// @return Vec<u8> 转换结束后的Ascii字符串
-    pub fn __utf8_to_ascii(&self, s: &str) -> Vec<u8> {
-        let mut ascii_str: Vec<u8> = Vec::with_capacity(s.len() + 1);
-        for byte in s.bytes() {
-            match byte {
-                0..=127 => {
-                    ascii_str.push(byte);
-                }
-                _ => {}
-            }
-        }
-        ascii_str.push(b'\0');
-        return ascii_str;
-    }
-
-    fn __write_string_on_stack(&self, s: &str) {
-        let s_len = s.len();
-        assert!(s_len < 1024, "s_len is too long");
-        let mut str_to_print: [u8; 1024] = [0; 1024];
-        let mut i = 0;
-        for byte in s.bytes() {
-            match byte {
-                0..=127 => {
-                    str_to_print[i] = byte;
-                    i += 1;
-                }
-                _ => {}
-            }
-        }
-        str_to_print[i] = b'\0';
-        unsafe {
-            printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
-        }
-    }
-
-    fn __write_string_color_on_stack(&self, fr_color: u32, bk_color: u32, s: &str) {
-        let s_len = s.len();
-        assert!(s_len < 1024, "s_len is too long");
-        let mut str_to_print: [u8; 1024] = [0; 1024];
-        let mut i = 0;
-        for byte in s.bytes() {
-            match byte {
-                0..=127 => {
-                    str_to_print[i] = byte;
-                    i += 1;
-                }
-                _ => {}
-            }
-        }
-        str_to_print[i] = b'\0';
-        unsafe {
-            printk_color(fr_color, bk_color, str_to_print.as_ptr() as *const c_char);
+    pub fn __write_string_color(&self, fr_color: FontColor, bk_color: FontColor, s: &str) {
+        for c in s.chars() {
+            textui_putchar(c, fr_color, bk_color).ok();
         }
     }
 }
@@ -219,6 +99,5 @@ impl fmt::Write for PrintkWriter {
 
 #[doc(hidden)]
 pub fn __printk(args: fmt::Arguments) {
-    use fmt::Write;
     PrintkWriter.write_fmt(args).unwrap();
 }

+ 1 - 0
kernel/src/libs/spinlock.rs

@@ -8,6 +8,7 @@ use core::sync::atomic::{AtomicBool, Ordering};
 
 use crate::arch::asm::irqflags::{local_irq_restore, local_irq_save};
 use crate::arch::interrupt::{cli, sti};
+
 use crate::include::bindings::bindings::{spin_lock, spin_unlock, spinlock_t};
 use crate::process::preempt::{preempt_disable, preempt_enable};
 use crate::syscall::SystemError;

+ 9 - 6
kernel/src/main.c

@@ -14,8 +14,8 @@
 #include "smp/smp.h"
 #include "syscall/syscall.h"
 #include <exception/softirq.h>
-#include <libs/libUI/screen_manager.h>
-#include <libs/libUI/textui.h>
+#include <libs/lib_ui/screen_manager.h>
+#include <libs/lib_ui/textui.h>
 #include <sched/sched.h>
 #include <smp/ipi.h>
 
@@ -71,10 +71,10 @@ void reload_idt()
 void system_initialize()
 {
     c_uart_init(COM1, 115200);
+
     video_init();
+
     scm_init();
-    textui_init();
-    kinfo("Kernel Starting...");
     // 重新加载gdt和idt
     ul tss_item_addr = (ul)phys_2_virt(0x7c00);
 
@@ -92,7 +92,6 @@ void system_initialize()
 
     // 初始化中断描述符表
     sys_vector_init();
-
     //  初始化内存管理单元
     // mm_init();
     rs_mm_init();
@@ -101,8 +100,12 @@ void system_initialize()
     // 原因是,系统启动初期,framebuffer被映射到48M地址处,
     // mm初始化完毕后,若不重新初始化显示驱动,将会导致错误的数据写入内存,从而造成其他模块崩溃
     // 对显示模块进行低级初始化,不启用double buffer
-    scm_reinit();
 
+    io_mfence();
+    scm_reinit();
+    rs_textui_init();
+    // kinfo("vaddr:%#018lx", video_frame_buffer_info.vaddr);
+    io_mfence();
     // =========== 重新设置initial_tss[0]的ist
     uchar *ptr = (uchar *)kzalloc(STACK_SIZE, 0) + STACK_SIZE;
     ((struct process_control_block *)(ptr - STACK_SIZE))->cpu_id = 0;

+ 2 - 1
kernel/src/mm/no_init.rs

@@ -1,6 +1,7 @@
 //! 该文件用于系统启动早期,内存管理器初始化之前,提供一些简单的内存映射功能
 //!
-//! 这里假设在内核引导文件中,已经填写了前100M的内存映射关系,因此这里不需要任何动态分配。
+//! 这里假设在内核引导文件中,已经填写了前100M的页表,其中,前50M是真实映射到内存的,后面的仅仅创建了页表,表项全部为0。
+//! 因此这里映射内存不需要任何动态分配。
 //!
 //! 映射关系为:
 //!

+ 0 - 1
tools/.gdbinit

@@ -1,4 +1,3 @@
 target remote localhost:1234
 file bin/kernel/kernel.elf
 set follow-fork-mode child 
-b Start_Kernel

+ 3 - 1
user/apps/shell/cmd.c

@@ -506,6 +506,7 @@ int shell_cmd_exec(int argc, char **argv)
         int path_len = 0;
         char *file_path = get_target_filepath(argv[1], &path_len);
         // printf("before execv, path=%s, argc=%d\n", file_path, argc);
+
         execv(file_path, argv);
         // printf("after execv, path=%s, argc=%d\n", file_path, argc);
         free(argv);
@@ -520,13 +521,14 @@ int shell_cmd_exec(int argc, char **argv)
             waitpid(pid, &retval, 0);
         else
             printf("[1] %d\n", pid); // 输出子进程的pid
-        
+
         free(argv);
     }
 }
 
 int shell_cmd_about(int argc, char **argv)
 {
+
     if (argv != NULL)
         free(argv);
     int aac = 0;

+ 4 - 0
user/apps/shell/shell.c

@@ -79,8 +79,12 @@ void main_loop(int kb_fd)
             strcpy(command_origin, input_buffer);
             int cmd_num = parse_command(input_buffer, &argc, &argv);
             printf("\n");
+          
+
             if (cmd_num >= 0)
                 shell_run_built_in_command(cmd_num, argc, argv);
+            
+            
         }
         else
             printf("\n");

+ 1 - 0
user/libs/libc/src/unistd.c

@@ -155,6 +155,7 @@ int execv(const char *path, char *const argv[])
         errno = -ENOENT;
         return -1;
     }
+
     int retval = syscall_invoke(SYS_EXECVE, (uint64_t)path, (uint64_t)argv, 0, 0, 0, 0, 0, 0);
     if (retval != 0)
         return -1;