From 602ec281a67a021117d932d8bc4711a318f69de4 Mon Sep 17 00:00:00 2001 From: fslongjin Date: Wed, 3 Aug 2022 17:13:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=86=E5=B1=8F=E5=B9=95?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=99=A8=E7=9A=84=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/common/printk.c | 28 +++++------ kernel/common/printk.h | 4 +- kernel/driver/video/video.c | 1 - kernel/lib/libUI/Makefile | 7 ++- kernel/lib/libUI/screen_manager.c | 79 +++++++++++++++++++++++++------ kernel/lib/libUI/screen_manager.h | 52 +++++++++++--------- kernel/lib/libUI/textui.c | 68 ++++++++++++++++++++++++++ kernel/lib/libUI/textui.h | 8 ++++ kernel/main.c | 19 ++++---- 9 files changed, 198 insertions(+), 68 deletions(-) create mode 100644 kernel/lib/libUI/textui.c create mode 100644 kernel/lib/libUI/textui.h diff --git a/kernel/common/printk.c b/kernel/common/printk.c index 760c21d3..6bc96350 100644 --- a/kernel/common/printk.c +++ b/kernel/common/printk.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include @@ -13,7 +15,7 @@ #include struct printk_screen_info pos; -extern ul VBE_FB_phys_addr; // 由bootloader传来的帧缓存区的物理地址 + static spinlock_t printk_lock; static bool sw_show_scroll_animation = false; // 显示换行动画的开关 @@ -81,24 +83,18 @@ static int calculate_max_charNum(int len, int size) return len / size - 1; } -int printk_init(const int char_size_x, const int char_size_y) +int printk_init(struct scm_buffer_info_t *buf) { - struct multiboot_tag_framebuffer_info_t info; - int reserved; - multiboot2_iter(multiboot2_get_Framebuffer_info, &info, &reserved); + pos.width = buf->width; + pos.height = buf->height; - pos.width = info.framebuffer_width; - pos.height = info.framebuffer_height; + pos.char_size_x = 8; + pos.char_size_y = 16; + pos.max_x = calculate_max_charNum(pos.width, pos.char_size_x); + pos.max_y = calculate_max_charNum(pos.height, pos.char_size_y); - pos.char_size_x = char_size_x; - pos.char_size_y = char_size_y; - pos.max_x = calculate_max_charNum(pos.width, char_size_x); - pos.max_y = calculate_max_charNum(pos.height, char_size_y); - - VBE_FB_phys_addr = (ul)info.framebuffer_addr; - - pos.FB_address = (uint *)0xffff800003000000; + pos.FB_address = buf->vaddr; pos.FB_length = 1UL * pos.width * pos.height; // 初始化自旋锁 @@ -108,7 +104,7 @@ int printk_init(const int char_size_x, const int char_size_y) pos.y = 0; cls(); - + io_mfence(); kdebug("width=%d\theight=%d", pos.width, pos.height); // 由于此时系统并未启用双缓冲,因此关闭滚动动画 diff --git a/kernel/common/printk.h b/kernel/common/printk.h index a7790499..c044d22c 100644 --- a/kernel/common/printk.h +++ b/kernel/common/printk.h @@ -33,7 +33,7 @@ #include "font.h" #include "glib.h" -//#include "linkage.h" +#include #include struct printk_screen_info @@ -61,7 +61,7 @@ extern unsigned char font_ascii[256][16]; //导出ascii字体的bitmap(8*16大 * @param char_size_x 字符的列坐标 * @param char_size_y 字符的行坐标 */ -int printk_init(const int char_size_x, const int char_size_y); +int printk_init(struct scm_buffer_info_t* buf); /** * @brief 将字符串按照fmt和args中的内容进行格式化,然后保存到buf中 diff --git a/kernel/driver/video/video.c b/kernel/driver/video/video.c index b40fd17e..79be713e 100644 --- a/kernel/driver/video/video.c +++ b/kernel/driver/video/video.c @@ -22,7 +22,6 @@ static struct scm_buffer_info_t *video_refresh_target = NULL; #define REFRESH_INTERVAL 15UL // 启动刷新帧缓冲区任务的时间间隔 -ul VBE_FB_phys_addr; // 由bootloader传来的帧缓存区的物理地址 /** * @brief VBE帧缓存区的地址重新映射 diff --git a/kernel/lib/libUI/Makefile b/kernel/lib/libUI/Makefile index 35fbd5ac..bbf427d1 100644 --- a/kernel/lib/libUI/Makefile +++ b/kernel/lib/libUI/Makefile @@ -1,7 +1,10 @@ -all: screen_manager.o +all: screen_manager.o textui.o CFLAGS += -I . screen_manager.o: screen_manager.c - gcc $(CFLAGS) -c screen_manager.c -o screen_manager.o \ No newline at end of file + gcc $(CFLAGS) -c screen_manager.c -o screen_manager.o + +textui.o: textui.c + gcc $(CFLAGS) -c textui.c -o textui.o \ No newline at end of file diff --git a/kernel/lib/libUI/screen_manager.c b/kernel/lib/libUI/screen_manager.c index d836248c..5c30f01a 100644 --- a/kernel/lib/libUI/screen_manager.c +++ b/kernel/lib/libUI/screen_manager.c @@ -1,4 +1,5 @@ #include "screen_manager.h" +#include #include #include #include @@ -7,13 +8,6 @@ #include #include -extern const struct scm_buffer_info_t video_frame_buffer_info; -static struct List scm_framework_list; -static spinlock_t scm_register_lock; // 框架注册锁 -static uint32_t scm_ui_max_id = 0; -static bool __scm_alloc_enabled = false; // 允许动态申请内存的标志位 -static bool __scm_double_buffer_enabled = false; // 允许双缓冲的标志位 - /** * @brief 初始化屏幕管理模块 * @@ -21,6 +15,14 @@ static bool __scm_double_buffer_enabled = false; // 允许双缓冲的标志位 #pragma GCC push_options #pragma GCC optimize("O0") +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 创建新的帧缓冲区 * @@ -35,7 +37,7 @@ static struct scm_buffer_info_t *__create_buffer(uint64_t type) struct scm_buffer_info_t *buf = (struct scm_buffer_info_t *)kmalloc(sizeof(struct scm_buffer_info_t), 0); if (buf == NULL) - return -ENOMEM; + 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; @@ -55,7 +57,7 @@ static struct scm_buffer_info_t *__create_buffer(uint64_t type) return buf; failed:; kfree(buf); - return -ENOMEM; + return (void*)-ENOMEM; } /** @@ -86,9 +88,12 @@ 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框架结构体中的参数设置是否合法 @@ -102,7 +107,7 @@ static int __check_ui_param(const char *name, const uint8_t type, const struct s { if (name == NULL) return -EINVAL; - if (type != SCM_FRAMWORK_TYPE_GUI || type != SCM_FRAMWORK_TYPE_TEXT) + if (!(type == SCM_FRAMWORK_TYPE_GUI || type == SCM_FRAMWORK_TYPE_TEXT)) return -EINVAL; if (ops == NULL) return -EINVAL; @@ -153,6 +158,8 @@ int scm_register_alloc(const char *name, const uint8_t type, struct scm_ui_frame // 调用ui框架的回调函数以安装ui框架,并将其激活 ui->ui_ops->install(ui->buf); ui->ui_ops->enable(NULL); + if (__current_framework == NULL) + return scm_framework_enable(ui); return 0; } @@ -170,11 +177,12 @@ int scm_register(struct scm_ui_framework_t *ui) return -EINVAL; list_init(&ui->list); - spin_lock(&video_frame_buffer_info); + spin_lock(&scm_register_lock); ui->id = scm_ui_max_id++; - spin_unlock(&video_frame_buffer_info); + spin_unlock(&scm_register_lock); ui->buf = __create_buffer(ui->type); + if ((uint64_t)(ui->buf) == (uint64_t)-ENOMEM) return -ENOMEM; @@ -184,6 +192,10 @@ int scm_register(struct scm_ui_framework_t *ui) // 调用ui框架的回调函数以安装ui框架,并将其激活 ui->ui_ops->install(ui->buf); ui->ui_ops->enable(NULL); + + if (__current_framework == NULL) + return scm_framework_enable(ui); + return 0; } @@ -225,6 +237,8 @@ int scm_enable_alloc() */ int scm_enable_double_buffer() { + if (__scm_double_buffer_enabled == true) + return 0; __scm_double_buffer_enabled = true; if (list_empty(&scm_framework_list)) return 0; @@ -235,9 +249,11 @@ int scm_enable_double_buffer() { if (ptr->buf == &video_frame_buffer_info) { + uart_send_str(COM1, "##init double buffer##"); struct scm_buffer_info_t *buf = __create_buffer(SCM_BF_DB | SCM_BF_PIXEL); if ((uint64_t)(buf) == (uint64_t)-ENOMEM) return -ENOMEM; + uart_send_str(COM1, "##to change double buffer##"); if (ptr->ui_ops->change(buf) != 0) { __destroy_buffer(buf); @@ -245,9 +261,11 @@ int scm_enable_double_buffer() } } } while (list_next(&ptr->list) != &scm_framework_list); - + // 设置定时刷新的对象 + video_set_refresh_target(__current_framework->buf); // 通知显示驱动,启动双缓冲 video_reinitialize(true); + uart_send_str(COM1, "##initialized double buffer##"); return 0; } @@ -261,8 +279,41 @@ 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) + { - return video_set_refresh_target(ui->buf); + retval = video_set_refresh_target(ui->buf); + if (retval == 0) + __current_framework = ui; + } + else + __current_framework = ui; + + 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; +} #pragma GCC pop_options \ No newline at end of file diff --git a/kernel/lib/libUI/screen_manager.h b/kernel/lib/libUI/screen_manager.h index 35fbe771..7ed2781f 100644 --- a/kernel/lib/libUI/screen_manager.h +++ b/kernel/lib/libUI/screen_manager.h @@ -33,11 +33,11 @@ struct scm_buffer_info_t */ struct scm_ui_framework_operations_t { - int (*install)(struct scm_buffer_info_t *buf); - int (*uninstall)(void *args); - int (*enable)(void *args); - int (*disable)(void *args); - int (*change)(struct scm_buffer_info_t *buf); + 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 { @@ -47,7 +47,7 @@ struct scm_ui_framework_t uint8_t type; struct scm_ui_framework_operations_t *ui_ops; struct scm_buffer_info_t *buf; -}__attribute__((aligned(sizeof(uint64_t)))); +} __attribute__((aligned(sizeof(uint64_t)))); /** * @brief 初始化屏幕管理模块 @@ -56,57 +56,63 @@ struct scm_ui_framework_t void scm_init(); /** - * @brief 向屏幕管理器注册UI框架(动态获取框架对象结构体) + * @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题 * + */ +void scm_reinit(); + +/** + * @brief 向屏幕管理器注册UI框架(动态获取框架对象结构体) + * * @param name 框架名 * @param type 类型 * @param ops 框架操作方法 - * @return int + * @return int */ -int scm_register_alloc(const char* name, const uint8_t type, struct scm_ui_framework_operations_t * ops); +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); +int scm_register(struct scm_ui_framework_t *ui); /** * @brief 向屏幕管理器卸载UI框架 - * + * * @param ui ui框架结构体 - * @return int + * @return int */ -int scm_unregister(struct scm_ui_framework_t*ui); +int scm_unregister(struct scm_ui_framework_t *ui); /** * @brief 向屏幕管理器卸载动态创建的UI框架 - * + * * @param ui ui框架结构体 - * @return int + * @return int */ -int scm_unregister_alloc(struct scm_ui_framework_t*ui); +int scm_unregister_alloc(struct scm_ui_framework_t *ui); /** * @brief 允许动态申请内存 - * - * @return int + * + * @return int */ int scm_enable_alloc(); /** * @brief 允许双缓冲区 - * - * @return int + * + * @return int */ int scm_enable_double_buffer(); /** * @brief 启用某个ui框架,将它的帧缓冲区渲染到屏幕上 - * + * * @param ui 要启动的ui框架 * @return int 返回码 */ -int scm_framework_enable(struct scm_ui_framework_t*ui); \ No newline at end of file +int scm_framework_enable(struct scm_ui_framework_t *ui); \ No newline at end of file diff --git a/kernel/lib/libUI/textui.c b/kernel/lib/libUI/textui.c new file mode 100644 index 00000000..940fa23c --- /dev/null +++ b/kernel/lib/libUI/textui.c @@ -0,0 +1,68 @@ +#include "textui.h" + +#include "screen_manager.h" +#include "driver/uart/uart.h" +#include +#include + +struct scm_ui_framework_t textui_framework; + +int textui_install_handler(struct scm_buffer_info_t *buf) +{ + return printk_init(buf); +} + +int textui_uninstall_handler(void *args) +{ +} + +int textui_enable_handler(void *args) +{ +} + +int textui_disable_handler(void *args) +{ +} + +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; + set_pos_VBE_FB_addr((uint*)buf->vaddr); + 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 初始化text ui框架 + * + * @return int + */ +int textui_init() +{ + memset(&textui_framework, 0, sizeof(textui_framework)); + io_mfence(); + char name[] = "textUI"; + strcpy(textui_framework.name, name); + + textui_framework.ui_ops = &textui_ops; + textui_framework.type = SCM_FRAMWORK_TYPE_TEXT; + uart_send_str(COM1, "12121"); + int retval = scm_register(&textui_framework); + if (retval != 0) + { + uart_send_str(COM1, "text ui init failed"); + while (1) + pause(); + } + uart_send_str(COM1, "text ui initialized"); + return 0; +} \ No newline at end of file diff --git a/kernel/lib/libUI/textui.h b/kernel/lib/libUI/textui.h new file mode 100644 index 00000000..30b39011 --- /dev/null +++ b/kernel/lib/libUI/textui.h @@ -0,0 +1,8 @@ +#pragma once + +/** + * @brief 初始化text ui框架 + * + * @return int + */ +int textui_init(); \ No newline at end of file diff --git a/kernel/main.c b/kernel/main.c index 1252104e..fd0f4e39 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -10,6 +10,7 @@ #include "exception/irq.h" #include #include +#include #include "mm/mm.h" #include "mm/slab.h" #include "process/process.h" @@ -73,14 +74,11 @@ void system_initialize() uart_init(COM1, 115200); video_init(); - // scm_init(); - // 初始化printk - printk_init(8, 16); - //#ifdef DEBUG - //#endif + scm_init(); + textui_init(); + kinfo("Kernel Starting..."); - while (1) - pause(); + // 重新加载gdt和idt ul tss_item_addr = (ul)phys_2_virt(0x7c00); @@ -106,7 +104,7 @@ void system_initialize() // 原因是,系统启动初期,framebuffer被映射到48M地址处, // mm初始化完毕后,若不重新初始化显示驱动,将会导致错误的数据写入内存,从而造成其他模块崩溃 // 对显示模块进行低级初始化,不启用double buffer - video_reinitialize(false); + scm_reinit(); // =========== 重新设置initial_tss[0]的ist @@ -165,8 +163,9 @@ void system_initialize() // kdebug("cpu_get_core_crysral_freq()=%ld", cpu_get_core_crysral_freq()); process_init(); - // 对显示模块进行高级初始化,启用double buffer - video_reinitialize(true); + // 启用double buffer + scm_enable_double_buffer(); + io_mfence(); // fat32_init();