From abe3a6ea3c543425e2cad12722e8a658b324d515 Mon Sep 17 00:00:00 2001 From: hanjiezhou Date: Sun, 20 Aug 2023 00:19:36 +0800 Subject: [PATCH] Patch refactor scm and textui (#289) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 重构屏幕管理器和textui框架 * 切换字体为spleen,并增加对字体的抽象 * 修正文档 --------- Co-authored-by: longjin --- .vscode/settings.json | 1 - docs/index.rst | 1 + docs/kernel/libs/index.rst | 12 + docs/kernel/libs/lib_ui/scm.md | 83 ++ docs/kernel/libs/lib_ui/textui.md | 32 + kernel/src/arch/x86_64/mm/mod.rs | 21 +- kernel/src/common/atomic.h | 4 +- kernel/src/common/font.h | 316 ------ kernel/src/common/printk.h | 24 +- kernel/src/driver/interrupt/apic/apic.c | 2 +- kernel/src/driver/tty/tty_device.rs | 13 +- kernel/src/driver/video/video.c | 43 +- kernel/src/driver/video/video.h | 16 +- kernel/src/head.S | 12 +- kernel/src/include/bindings/wrapper.h | 2 +- kernel/src/lib.rs | 8 +- kernel/src/libs/Makefile | 2 +- kernel/src/libs/libUI/Makefile | 13 - kernel/src/libs/libUI/screen_manager.c | 351 ------- kernel/src/libs/libUI/screen_manager.h | 120 --- kernel/src/libs/libUI/textui-render.c | 154 --- kernel/src/libs/libUI/textui.c | 372 ------- kernel/src/libs/libUI/textui.h | 187 ---- .../font/binaries/spleen-8x16.raw_bytes | Bin 0 -> 4096 bytes kernel/src/libs/lib_ui/font/mod.rs | 90 ++ kernel/src/libs/lib_ui/font/spleen_font.rs | 25 + kernel/src/libs/lib_ui/mod.rs | 4 + kernel/src/libs/lib_ui/screen_manager.h | 58 ++ kernel/src/libs/lib_ui/screen_manager.rs | 475 +++++++++ kernel/src/libs/lib_ui/textui.h | 19 + kernel/src/libs/lib_ui/textui.rs | 967 ++++++++++++++++++ kernel/src/libs/lib_ui/textui_no_alloc.rs | 125 +++ kernel/src/libs/mod.rs | 1 + kernel/src/libs/printk.c | 4 +- kernel/src/libs/printk.rs | 147 +-- kernel/src/libs/spinlock.rs | 1 + kernel/src/main.c | 15 +- kernel/src/mm/no_init.rs | 3 +- tools/.gdbinit | 1 - user/apps/shell/cmd.c | 4 +- user/apps/shell/shell.c | 4 + user/libs/libc/src/unistd.c | 1 + 42 files changed, 2006 insertions(+), 1727 deletions(-) create mode 100644 docs/kernel/libs/index.rst create mode 100644 docs/kernel/libs/lib_ui/scm.md create mode 100644 docs/kernel/libs/lib_ui/textui.md delete mode 100644 kernel/src/common/font.h delete mode 100644 kernel/src/libs/libUI/Makefile delete mode 100644 kernel/src/libs/libUI/screen_manager.c delete mode 100644 kernel/src/libs/libUI/screen_manager.h delete mode 100644 kernel/src/libs/libUI/textui-render.c delete mode 100644 kernel/src/libs/libUI/textui.c delete mode 100644 kernel/src/libs/libUI/textui.h create mode 100644 kernel/src/libs/lib_ui/font/binaries/spleen-8x16.raw_bytes create mode 100644 kernel/src/libs/lib_ui/font/mod.rs create mode 100644 kernel/src/libs/lib_ui/font/spleen_font.rs create mode 100644 kernel/src/libs/lib_ui/mod.rs create mode 100644 kernel/src/libs/lib_ui/screen_manager.h create mode 100644 kernel/src/libs/lib_ui/screen_manager.rs create mode 100644 kernel/src/libs/lib_ui/textui.h create mode 100644 kernel/src/libs/lib_ui/textui.rs create mode 100644 kernel/src/libs/lib_ui/textui_no_alloc.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 3593bba15..c21797a62 100644 --- a/.vscode/settings.json +++ b/.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", diff --git a/docs/index.rst b/docs/index.rst index 9f42f652f..d5103e30d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -29,6 +29,7 @@ kernel/debug/index kernel/ktest/index kernel/cpu_arch/index + kernel/libs/index .. toctree:: diff --git a/docs/kernel/libs/index.rst b/docs/kernel/libs/index.rst new file mode 100644 index 000000000..b7987c766 --- /dev/null +++ b/docs/kernel/libs/index.rst @@ -0,0 +1,12 @@ +==================================== +其他内核库 +==================================== + + 这里的集中了内核中的一些库的文档,这些库不属于任何子系统。 + +.. toctree:: + :maxdepth: 1 + + lib_ui/scm + lib_ui/textui + diff --git a/docs/kernel/libs/lib_ui/scm.md b/docs/kernel/libs/lib_ui/scm.md new file mode 100644 index 000000000..418f13fe9 --- /dev/null +++ b/docs/kernel/libs/lib_ui/scm.md @@ -0,0 +1,83 @@ +# 屏幕管理器(SCM) + +:::{note} +作者: 周瀚杰 <2625553453@qq.com> +::: +  屏幕管理器用来管理控制所有ui框架,所有框架都必须先在屏幕管理器中注册才可使用,然后scm控制当前是哪个ui框架在使用 + +## traits + +### ScmUiFramework +  每个要注册到scm中的ui框架都必须实现这个trait中的方法,具体定义如下: +```rust +pub trait ScmUiFramework: Sync + Send + Debug { + // 安装ui框架的回调函数 + fn install(&self) -> Result { + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } + // 卸载ui框架的回调函数 + fn uninstall(&self) -> Result { + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } + // 启用ui框架的回调函数 + fn enable(&self) -> Result { + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } + // 禁用ui框架的回调函数 + fn disable(&self) -> Result { + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } + // 改变ui框架的帧缓冲区的回调函数 + fn change(&self, _buf: ScmBufferInfo) -> Result { + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } + /// @brief 获取ScmUiFramework的元数据 + /// @return 成功:Ok(ScmUiFramework的元数据) + /// 失败:Err(错误码) + fn metadata(&self) -> Result { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } +} +``` +## 主要API +### scm_init() -初始化屏幕管理模块 +#### 原型 +```rust +pub extern "C" fn scm_init() +``` +#### 说明 +  scm_init()主要是初始化一些scm中使用的全局变量,例如是否使用双缓冲区标志位,textui未初始化时使用的一些全局变量 + +### scm_reinit() -当内存管理单元被初始化之后,重新初始化屏幕管理模块 +#### 原型 +```rust +pub extern "C" fn scm_reinit() -> i32 +``` +#### 说明 +  scm_reinit()用于当内存管理单元被初始化之后,重新处理帧缓冲区问题 + +### scm_enable_double_buffer() -允许双缓冲区 +#### 原型 +```rust +pub extern "C" fn scm_enable_double_buffer() -> i32 +``` +#### 说明 +  scm_enable_double_buffer()用于启动双缓冲来往窗口输出打印信息。启用后,往窗口输出的信息会暂时放在一个缓冲区中,然后每次按一定时间将该缓冲区的信息输出到窗口帧缓冲区中,渲染显示到窗口上。 + +### scm_framework_enable() -启用某个ui框架,将它的帧缓冲区渲染到屏幕上 +#### 原型 +```rust +pub fn scm_framework_enable(framework: Arc) -> Result +``` +#### 说明 +  scm_framework_enable用于启用某个ui框架,将它的帧缓冲区渲染到屏幕上 + + +### scm_register() -向屏幕管理器注册UI框架 +#### 原型 +```rust +pub fn scm_register(framework: Arc) -> Result +``` +#### 说明 +  scm_register用于将ui框架注册到scm中,主要是调用ui框架的回调函数以安装ui框架,并将其激活 diff --git a/docs/kernel/libs/lib_ui/textui.md b/docs/kernel/libs/lib_ui/textui.md new file mode 100644 index 000000000..a5683aa41 --- /dev/null +++ b/docs/kernel/libs/lib_ui/textui.md @@ -0,0 +1,32 @@ +# 文本显示框架(textui) + +:::{note} +作者: 周瀚杰 <2625553453@qq.com> +::: +  文本框架主要用于DragonOS的文本的窗口渲染显示,往屏幕窗口中输出打印文本信息,往窗口显示文本分成两种情况:一种是当内存管理单元(mm)未被初始化时,不能进行动态内存分配,限制颇多(例如不能使用vec,mpsc等),所以直接往窗口的帧缓冲区输出打印信息,不使用虚拟行等复杂结构体;另一种是当内存管理单元(mm)已经初始化,可以进行动态内存分配,便可以使用一些复杂的结构体来处理要打印的文本信息。 + + +## 主要API +### rs_textui_init() -textui框架初始化 +#### 原型 +```rust +pub extern "C" fn rs_textui_init() -> i32 +``` +#### 说明 +  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> +``` +#### 说明 +  textui_putchar()要处理两种情况:一种是当内存管理单元(mm)未被初始化时,不能进行动态内存分配,限制颇多(例如不能使用vec,mpsc等),所以直接往窗口的帧缓冲区输出打印信息,不使用虚拟行等复杂结构体;另一种是当内存管理单元(mm)已经初始化,可以进行动态内存分配,便可以使用一些复杂的结构体来处理要打印的文本信息。 + + diff --git a/kernel/src/arch/x86_64/mm/mod.rs b/kernel/src/arch/x86_64/mm/mod.rs index 0f27cea00..66952ba5a 100644 --- a/kernel/src/arch/x86_64/mm/mod.rs +++ b/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] diff --git a/kernel/src/common/atomic.h b/kernel/src/common/atomic.h index 77b4d3ac7..889818186 100644 --- a/kernel/src/common/atomic.h +++ b/kernel/src/common/atomic.h @@ -11,8 +11,8 @@ #pragma once #include -#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 { diff --git a/kernel/src/common/font.h b/kernel/src/common/font.h deleted file mode 100644 index bc68b86b3..000000000 --- a/kernel/src/common/font.h +++ /dev/null @@ -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}, - - -}; - diff --git a/kernel/src/common/printk.h b/kernel/src/common/printk.h index 74977743d..be15e5f1d 100644 --- a/kernel/src/common/printk.h +++ b/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 +#include #include -extern unsigned char font_ascii[256][16]; //导出ascii字体的bitmap(8*16大小) ps:位于font.h中 - - /** * @brief 将字符串按照fmt和args中的内容进行格式化,然后保存到buf中 * diff --git a/kernel/src/driver/interrupt/apic/apic.c b/kernel/src/driver/interrupt/apic/apic.c index 31a043b50..1339a4060 100644 --- a/kernel/src/driver/interrupt/apic/apic.c +++ b/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 diff --git a/kernel/src/driver/tty/tty_device.rs b/kernel/src/driver/tty/tty_device.rs index bdc82c635..64549af15 100644 --- a/kernel/src/driver/tty/tty_device.rs +++ b/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(()); diff --git a/kernel/src/driver/video/video.c b/kernel/src/driver/video/video.c index 6bbfc3138..dd916a8e1 100644 --- a/kernel/src/driver/video/video.c +++ b/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; } \ No newline at end of file diff --git a/kernel/src/driver/video/video.h b/kernel/src/driver/video/video.h index a2cf60c4b..767e76e67 100644 --- a/kernel/src/driver/video/video.h +++ b/kernel/src/driver/video/video.h @@ -1,8 +1,8 @@ #pragma once #include #include -#include - +#include +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); \ No newline at end of file +void video_refresh_framebuffer(void *data); +uint64_t get_video_refresh_target_vaddr(); \ No newline at end of file diff --git a/kernel/src/head.S b/kernel/src/head.S index 196774602..7929762fa 100644 --- a/kernel/src/head.S +++ b/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寄存器 diff --git a/kernel/src/include/bindings/wrapper.h b/kernel/src/include/bindings/wrapper.h index 564e15fe8..82d79699f 100644 --- a/kernel/src/include/bindings/wrapper.h +++ b/kernel/src/include/bindings/wrapper.h @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index c5eb386f3..6efa09df0 100644 --- a/kernel/src/lib.rs +++ b/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()); diff --git a/kernel/src/libs/Makefile b/kernel/src/libs/Makefile index e32833424..90cda8f17 100644 --- a/kernel/src/libs/Makefile +++ b/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) diff --git a/kernel/src/libs/libUI/Makefile b/kernel/src/libs/libUI/Makefile deleted file mode 100644 index 209e0562e..000000000 --- a/kernel/src/libs/libUI/Makefile +++ /dev/null @@ -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 diff --git a/kernel/src/libs/libUI/screen_manager.c b/kernel/src/libs/libUI/screen_manager.c deleted file mode 100644 index 145ba3b30..000000000 --- a/kernel/src/libs/libUI/screen_manager.c +++ /dev/null @@ -1,351 +0,0 @@ -#include "screen_manager.h" -#include -#include -#include -#include -#include -#include -#include -#include - -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; -} diff --git a/kernel/src/libs/libUI/screen_manager.h b/kernel/src/libs/libUI/screen_manager.h deleted file mode 100644 index 411c3ee40..000000000 --- a/kernel/src/libs/libUI/screen_manager.h +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once -#include -#include - -// 帧缓冲区标志位 -#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); \ No newline at end of file diff --git a/kernel/src/libs/libUI/textui-render.c b/kernel/src/libs/libUI/textui-render.c deleted file mode 100644 index 5fc985f0c..000000000 --- a/kernel/src/libs/libUI/textui-render.c +++ /dev/null @@ -1,154 +0,0 @@ -#include "textui.h" -#include -#include -#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; - } -} \ No newline at end of file diff --git a/kernel/src/libs/libUI/textui.c b/kernel/src/libs/libUI/textui.c deleted file mode 100644 index faa9af613..000000000 --- a/kernel/src/libs/libUI/textui.c +++ /dev/null @@ -1,372 +0,0 @@ -#include "textui.h" - -#include -#include "screen_manager.h" -#include -#include -#include -#include - -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); -} \ No newline at end of file diff --git a/kernel/src/libs/libUI/textui.h b/kernel/src/libs/libUI/textui.h deleted file mode 100644 index 2351c477d..000000000 --- a/kernel/src/libs/libUI/textui.h +++ /dev/null @@ -1,187 +0,0 @@ -#pragma once -#include -#include -#include - -/* -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(); diff --git a/kernel/src/libs/lib_ui/font/binaries/spleen-8x16.raw_bytes b/kernel/src/libs/lib_ui/font/binaries/spleen-8x16.raw_bytes new file mode 100644 index 0000000000000000000000000000000000000000..a132b3b5e38a57643c7a6158dfa6db34f3d0a39e GIT binary patch literal 4096 zcmeHKKWiOF5MLs5xLCv^h1fy}SFR5m!WD-xE>h_Oq`c~?!@SCva2!FOAVo;wQl-k2 zsSX>C6vsn^a6F7r`6^*l2^EjCfAeSm+=F}qdu*-lw=+94J2SgGGNv6e>+;;-Kht;o zZN)>f9!Do+oa4C~6q)#Hnz;dC;OSL&eSO`Yfc7h%$m+&Am;Y2(3{3&yV*PO(e`QSC zg(2fHYOi9-b9Zda+F6@1S?ks;Qy}DL3^qk0ja~foU%KMxD9fOkt@b^b z?J#U^?svn`ili&v{=y+p9XJnE5Y;dXpKu8Wy?oz~pxIh0{CVj6eZp@E4~ZWdi9U&&*aY_^5i@H z412*{ucRiJcffxj5#^IS<36sxA$jG~XKD|r74qvnzLWJ3A0I|qC0M-)_J+^%L|o4w zhTU$OHXDy=e@wbx-XALweafGv)^SFe&kLgeE%KXbJid7Uw5(P8Vt<%xidFC*aGF1> z|IBM>RpcZ6LH{h}*Y`8?U!ZUTy)dTls|qKFPtDO0${B?i2wPkgjVc!PixDbOIEyI) zZPvjZjXy#|Aqe>gUrIpv@RX#3Jn@mykdHHX+p@=`nn~mlL<(WhuWq8aHKHOMvE%yy z^5gdIZab=c2*#<%W4xU}KAynhe++}97{O7}{Xw%#=zg#>kHPXxOkw}(JV4mqnFwR# zaQOHs4*6$H4!(}^O@S;$|8#v)0(1c(S)gMM&U($ia9{dhF$PqIiW&2)JEvv;Plxxx zcl@ot|GuPr%{=b@A?hCUMA6{2eyA$Fk7%wg(Iof>`ojmj*Yr>CLoG~SpJiR;Bwm*` zt4l1_K7w`g&|bW|yu5sOA?LHO<#}o1S!I#u^;kcTD-7;PJ*s|^G%K|ie_#D|b*1_a zG*Np}cuD_T`U|<=igR03$)eMzHhX&NC5^$!j6lDrAsEMdxiUH&^*7WXog{KTILVZD zFs?wP67R*o!~t4@-Pfb6ec8W!_4BRE*Z=)-_UMr@9ykA9*cGm%>h~u<{@Fx6H52H5 zs$Tk$+))E04=^djZWg#`miXEE5+i#D^2GwHPl~yn@8AQwO9Pd_r1|G~u( { + /// 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() + } +} diff --git a/kernel/src/libs/lib_ui/font/spleen_font.rs b/kernel/src/libs/lib_ui/font/spleen_font.rs new file mode 100644 index 000000000..6ef9aebc6 --- /dev/null +++ b/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), +); diff --git a/kernel/src/libs/lib_ui/mod.rs b/kernel/src/libs/lib_ui/mod.rs new file mode 100644 index 000000000..fa628ea56 --- /dev/null +++ b/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; diff --git a/kernel/src/libs/lib_ui/screen_manager.h b/kernel/src/libs/lib_ui/screen_manager.h new file mode 100644 index 000000000..101600dc4 --- /dev/null +++ b/kernel/src/libs/lib_ui/screen_manager.h @@ -0,0 +1,58 @@ +#pragma once +#include +#include + +// 帧缓冲区标志位 +#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(); diff --git a/kernel/src/libs/lib_ui/screen_manager.rs b/kernel/src/libs/lib_ui/screen_manager.rs new file mode 100644 index 000000000..5689329c5 --- /dev/null +++ b/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>> = + SpinLock::new(LinkedList::new()); + /// 当前在使用的UI框架 + pub static ref CURRENT_FRAMEWORK: RwLock>> = 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), + DoubleBuffer(Option>), +} +#[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` 创建成功返回新的帧缓冲区结构体,创建失败返回错误码 + pub fn new(buf_type: ScmBufferFlag) -> Result { + 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 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 { + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } + // 卸载ui框架的回调函数 + fn uninstall(&self) -> Result { + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } + // 启用ui框架的回调函数 + fn enable(&self) -> Result { + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } + // 禁用ui框架的回调函数 + fn disable(&self) -> Result { + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } + // 改变ui框架的帧缓冲区的回调函数 + fn change(&self, _buf: ScmBufferInfo) -> Result { + return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); + } + /// @brief 获取ScmUiFramework的元数据 + /// @return 成功:Ok(ScmUiFramework的元数据) + /// 失败:Err(错误码) + fn metadata(&self) -> Result { + // 若文件系统没有实现此方法,则返回“不支持” + 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) -> Result { + // 获取信息 + 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) -> Result { + // 把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 { + 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 { + 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); +} diff --git a/kernel/src/libs/lib_ui/textui.h b/kernel/src/libs/lib_ui/textui.h new file mode 100644 index 000000000..b18c248d2 --- /dev/null +++ b/kernel/src/libs/lib_ui/textui.h @@ -0,0 +1,19 @@ +#pragma once +#include + +/** + * @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(); \ No newline at end of file diff --git a/kernel/src/libs/lib_ui/textui.rs b/kernel/src/libs/lib_ui/textui.rs new file mode 100644 index 000000000..1c60bbd18 --- /dev/null +++ b/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> = 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> = Arc::new(SpinLock::new(initial_window)); + + let default_window = current_window.clone(); + + // 生成窗口链表,并把上面窗口添加进textui框架的窗口链表中 + let window_list: Arc>>>> = + 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 for LineId { + type Output = LineId; + fn add(self, rhs: i32) -> Self::Output { + LineId::new(self.0 + rhs) + } +} +impl Sub for LineId { + type Output = LineId; + + fn sub(self, rhs: i32) -> Self::Output { + LineId::new(self.0 - rhs) + } +} + +impl Into for LineId { + fn into(self) -> i32 { + self.0.clone() + } +} +impl Into for LineId { + fn into(self) -> u32 { + self.0.clone() as u32 + } +} +impl Into for LineId { + fn into(self) -> usize { + self.0.clone() as usize + } +} +impl Sub for LineId { + type Output = LineId; + + fn sub(mut self, rhs: LineId) -> Self::Output { + self.0 -= rhs.0; + return self; + } +} +impl AddAssign 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 for LineIndex { + type Output = LineIndex; + + fn add(self, rhs: LineIndex) -> Self::Output { + LineIndex::new(self.0 + rhs.0) + } +} +impl Add for LineIndex { + // type Output = Self; + type Output = LineIndex; + + fn add(self, rhs: i32) -> Self::Output { + LineIndex::new(self.0 + rhs) + } +} +impl Sub for LineIndex { + type Output = LineIndex; + + fn sub(self, rhs: i32) -> Self::Output { + LineIndex::new(self.0 - rhs) + } +} + +impl Into for LineIndex { + fn into(self) -> i32 { + self.0.clone() + } +} +impl Into for LineIndex { + fn into(self) -> u32 { + self.0.clone() as u32 + } +} +impl Into 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 for FontColor { + fn from(value: u32) -> Self { + return Self(value & 0x00ffffff); + } +} +impl Into for FontColor { + fn into(self) -> usize { + self.0.clone() as usize + } +} +impl Into for FontColor { + fn into(self) -> u32 { + self.0.clone() + } +} +impl Into for FontColor { + fn into(self) -> u16 { + self.0.clone() as u16 + } +} +impl Into for FontColor { + fn into(self) -> u64 { + self.0.clone() as u64 + } +} + +/// 彩色字符对象 + +#[derive(Clone, Debug, Copy)] +pub struct TextuiCharChromatic { + c: Option, + + // 前景色 + 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, frcolor: FontColor, bkcolor: FontColor) -> Self { + TextuiCharChromatic { + c, + frcolor, + bkcolor, + } + } + + /// 将该字符对象输出到缓冲区 + /// ## 参数 + /// -line_id 要放入的真实行号 + /// -index 要放入的真实列号 + pub fn textui_refresh_character( + &self, + lineid: LineId, + lineindex: LineIndex, + ) -> Result { + // 找到要渲染的字符的像素点数据 + + 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, // 字符对象数组 + _index: i16, // 当前操作的位置 +} +/// 彩色显示的虚拟行结构体 + +#[derive(Clone, Debug, Default)] +pub struct TextuiVlineChromatic { + chars: Vec, // 字符对象数组 + 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, + // 正在操作的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) + || (>::into(start) + count) > self.chars_per_line, + ) { + return Err(SystemError::EINVAL); + } + // 计算虚拟行对应的真实行(即要渲染的行) + let mut actual_line_id = vline_id - self.top_vline; //为正说明虚拟行不在真实行显示的区域上面 + + if >::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[>::into(vline_id)]; + let mut i = 0; + let mut index = start; + + while i < count { + if let TextuiVline::Chromatic(vline) = vline { + vline.chars[>::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 { + let mut refresh_count = count; + for i in >::into(start) + ..(self.vline_sum).min(>::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 { + // 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[>::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[>::into(self.vline_operating)]) + { + let index = >::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[>::into(self.vline_operating)] + { + //打印的空格数(注意将每行分成一个个表格,每个表格为8个字符) + let mut space_to_print = 8 - >::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[>::into(self.vline_operating)] + { + vline.index = vline.index - 1; + tmp = vline.index; + } + if >::into(tmp) >= 0 { + if let TextuiVline::Chromatic(vline) = + &mut self.vlines[>::into(self.vline_operating)] + { + if let Some(v_char) = + vline.chars.get_mut(>::into(tmp)) + { + v_char.c = Some(' '); + + v_char.bkcolor = bkcolor; + } + } + return self.textui_refresh_characters(self.vline_operating, tmp, 1); + } + // 需要向上缩一行 + if >::into(tmp) < 0 { + // 当前行为空,需要重新刷新 + if let TextuiVline::Chromatic(vline) = + &mut self.vlines[>::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 >::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[>::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>>>>, + actual_line: AtomicI32, // 真实行的数量(textui的帧缓冲区能容纳的内容的行数) + current_window: Arc>, // 当前的主窗口 + default_window: Arc>, // 默认print到的窗口 +} + +impl TextUiFramework { + pub fn new( + metadata: ScmUiFrameworkMetadata, + window_list: Arc>>>>, + current_window: Arc>, + default_window: Arc>, + ) -> 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 { + c_uart_send_str( + UartPort::COM1.to_u16(), + "\ntextui_install_handler\n\0".as_ptr(), + ); + return Ok(0); + } + // 卸载ui框架的回调函数 + fn uninstall(&self) -> Result { + return Ok(0); + } + // 启用ui框架的回调函数 + fn enable(&self) -> Result { + ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst); + return Ok(0); + } + // 禁用ui框架的回调函数 + fn disable(&self) -> Result { + ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst); + + return Ok(0); + } + // 改变ui框架的帧缓冲区的回调函数 + fn change(&self, buf_info: ScmBufferInfo) -> Result { + 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 { + 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 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 { + 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); +} diff --git a/kernel/src/libs/lib_ui/textui_no_alloc.rs b/kernel/src/libs/lib_ui/textui_no_alloc.rs new file mode 100644 index 000000000..82de0a366 --- /dev/null +++ b/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(()); +} diff --git a/kernel/src/libs/mod.rs b/kernel/src/libs/mod.rs index 46e83fba6..d7149f01c 100644 --- a/kernel/src/libs/mod.rs +++ b/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; diff --git a/kernel/src/libs/printk.c b/kernel/src/libs/printk.c index 4e9cf1900..2db0c4bc2 100644 --- a/kernel/src/libs/printk.c +++ b/kernel/src/libs/printk.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include @@ -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); diff --git a/kernel/src/libs/printk.rs b/kernel/src/libs/printk.rs index 5a925fbc6..4eb00386d 100644 --- a/kernel/src/libs/printk.rs +++ b/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 转换结束后的Ascii字符串 - pub fn __utf8_to_ascii(&self, s: &str) -> Vec { - let mut ascii_str: Vec = 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(); } diff --git a/kernel/src/libs/spinlock.rs b/kernel/src/libs/spinlock.rs index 1108b12f8..1da47b74d 100644 --- a/kernel/src/libs/spinlock.rs +++ b/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; diff --git a/kernel/src/main.c b/kernel/src/main.c index a288e32ea..9c860719c 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.c @@ -14,8 +14,8 @@ #include "smp/smp.h" #include "syscall/syscall.h" #include -#include -#include +#include +#include #include #include @@ -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; diff --git a/kernel/src/mm/no_init.rs b/kernel/src/mm/no_init.rs index 352cd396d..b481e9f3f 100644 --- a/kernel/src/mm/no_init.rs +++ b/kernel/src/mm/no_init.rs @@ -1,6 +1,7 @@ //! 该文件用于系统启动早期,内存管理器初始化之前,提供一些简单的内存映射功能 //! -//! 这里假设在内核引导文件中,已经填写了前100M的内存映射关系,因此这里不需要任何动态分配。 +//! 这里假设在内核引导文件中,已经填写了前100M的页表,其中,前50M是真实映射到内存的,后面的仅仅创建了页表,表项全部为0。 +//! 因此这里映射内存不需要任何动态分配。 //! //! 映射关系为: //! diff --git a/tools/.gdbinit b/tools/.gdbinit index d086b3558..d15f57ec7 100644 --- a/tools/.gdbinit +++ b/tools/.gdbinit @@ -1,4 +1,3 @@ target remote localhost:1234 file bin/kernel/kernel.elf set follow-fork-mode child -b Start_Kernel \ No newline at end of file diff --git a/user/apps/shell/cmd.c b/user/apps/shell/cmd.c index 87b060492..7657f122a 100644 --- a/user/apps/shell/cmd.c +++ b/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; diff --git a/user/apps/shell/shell.c b/user/apps/shell/shell.c index 91ca586b9..9c704e640 100644 --- a/user/apps/shell/shell.c +++ b/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"); diff --git a/user/libs/libc/src/unistd.c b/user/libs/libc/src/unistd.c index 8c79fde10..d808ddc5a 100644 --- a/user/libs/libc/src/unistd.c +++ b/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;