diff --git a/.vscode/settings.json b/.vscode/settings.json index 82dc5551..7aa52e35 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -116,7 +116,8 @@ "apic_timer.h": "c", "sched.h": "c", "preempt.h": "c", - "softirq.h": "c" + "softirq.h": "c", + "screen_manager.h": "c" }, "C_Cpp.errorSquiggles": "Enabled", "esbonio.sphinx.confDir": "" diff --git a/Makefile b/Makefile index 1a87b4c1..f3592417 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ export ARCH=__x86_64__ export ROOT_PATH=$(shell pwd) export DEBUG=DEBUG -export GLOBAL_CFLAGS := -mcmodel=large -fno-builtin -m64 -fno-stack-protector -D $(ARCH) -O1 +export GLOBAL_CFLAGS := -mcmodel=large -fno-builtin -m64 -fno-stack-protector -D $(ARCH) -O0 ifeq ($(DEBUG), DEBUG) GLOBAL_CFLAGS += -g diff --git a/kernel/common/printk.c b/kernel/common/printk.c index a2414a80..07c786a3 100644 --- a/kernel/common/printk.c +++ b/kernel/common/printk.c @@ -103,38 +103,17 @@ int printk_init(const int char_size_x, const int char_size_y) // 初始化自旋锁 spin_init(&printk_lock); - // ======== 临时的将物理地址填写到0x0000000003000000处 之后会在mm内将帧缓存区重新映射===== - - ul global_CR3 = (ul)get_CR3(); - ul fb_virt_addr = (ul)pos.FB_address; - ul fb_phys_addr = VBE_FB_phys_addr; - - // 计算帧缓冲区的线性地址对应的pml4页表项的地址 - ul *tmp = phys_2_virt((ul *)((ul)global_CR3 & (~0xfffUL)) + ((fb_virt_addr >> PAGE_GDT_SHIFT) & 0x1ff)); - - tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((fb_virt_addr >> PAGE_1G_SHIFT) & 0x1ff)); - - ul *tmp1; - // 初始化2M物理页 - for (ul i = 0; i < (pos.FB_length << 2); i += PAGE_2M_SIZE) - { - // 计算当前2M物理页对应的pdt的页表项的物理地址 - tmp1 = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + (((fb_virt_addr + i) >> PAGE_2M_SHIFT) & 0x1ff)); - - // 页面写穿,禁止缓存 - set_pdt(tmp1, mk_pdt((ul)fb_phys_addr + i, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD)); - } - - flush_tlb(); - pos.x = 0; pos.y = 0; cls(); - + + io_mfence(); kdebug("width=%d\theight=%d", pos.width, pos.height); // 由于此时系统并未启用双缓冲,因此关闭滚动动画 printk_disable_animation(); + + io_mfence(); return 0; } @@ -960,4 +939,3 @@ int sprintk(char *buf, const char *fmt, ...) return count; } - diff --git a/kernel/driver/video/video.c b/kernel/driver/video/video.c index c1e14357..b40fd17e 100644 --- a/kernel/driver/video/video.c +++ b/kernel/driver/video/video.c @@ -8,62 +8,37 @@ #include #include #include +#include +#include + -// 每个时刻只能有1个进程新增定时任务 -spinlock_t video_timer_func_add_lock; 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; + #define REFRESH_INTERVAL 15UL // 启动刷新帧缓冲区任务的时间间隔 ul VBE_FB_phys_addr; // 由bootloader传来的帧缓存区的物理地址 -struct screen_info_t -{ - int width, height; - uint64_t length; - uint64_t fb_vaddr, fb_paddr; - uint64_t double_fb_vaddr; -} sc_info; /** * @brief VBE帧缓存区的地址重新映射 * 将帧缓存区映射到地址SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE处 */ -void init_frame_buffer(bool level) +void init_frame_buffer() { kinfo("Re-mapping VBE frame buffer..."); uint64_t global_CR3 = (uint64_t)get_CR3(); - if (level == false) - { - struct multiboot_tag_framebuffer_info_t info; - int reserved; + struct multiboot_tag_framebuffer_info_t info; + int reserved; - multiboot2_iter(multiboot2_get_Framebuffer_info, &info, &reserved); - - sc_info.fb_vaddr = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + FRAME_BUFFER_MAPPING_OFFSET; - - sc_info.fb_paddr = info.framebuffer_addr; - sc_info.width = info.framebuffer_width; - sc_info.height = info.framebuffer_height; - - sc_info.length = 1UL * sc_info.width * sc_info.height; - mm_map_proc_page_table(global_CR3, true, sc_info.fb_vaddr, sc_info.fb_paddr, get_VBE_FB_length() << 2, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false, true, false); - set_pos_VBE_FB_addr((uint *)sc_info.fb_vaddr); - } - else // 高级初始化,增加双缓冲区的支持 - { - // 申请双重缓冲区 - struct Page *p = alloc_pages(ZONE_NORMAL, PAGE_2M_ALIGN(sc_info.length << 2) / PAGE_2M_SIZE, 0); - sc_info.double_fb_vaddr = (uint64_t)phys_2_virt(p->addr_phys); - mm_map_proc_page_table(global_CR3, true, sc_info.double_fb_vaddr, p->addr_phys, PAGE_2M_ALIGN(sc_info.length << 2), PAGE_KERNEL_PAGE, false, true, false); - - // 将原有的数据拷贝到double buffer里面 - memcpy((void *)sc_info.double_fb_vaddr, (void *)sc_info.fb_vaddr, sc_info.length << 2); - set_pos_VBE_FB_addr((uint *)sc_info.double_fb_vaddr); - } + video_frame_buffer_info.vaddr = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + FRAME_BUFFER_MAPPING_OFFSET; + mm_map_proc_page_table(global_CR3, true, video_frame_buffer_info.vaddr, __fb_info.framebuffer_addr, video_frame_buffer_info.size, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false, true, false); flush_tlb(); kinfo("VBE frame buffer successfully Re-mapped!"); @@ -76,7 +51,9 @@ void init_frame_buffer(bool level) void video_refresh_framebuffer(void *data) { video_refresh_expire_jiffies = cal_next_n_ms_jiffies(REFRESH_INTERVAL << 1); - memcpy((void *)sc_info.fb_vaddr, (void *)sc_info.double_fb_vaddr, (sc_info.length << 2)); + if (unlikely(video_refresh_target == NULL)) + return; + memcpy((void *)video_frame_buffer_info.vaddr, (void *)video_refresh_target->vaddr, video_refresh_target->size); } /** @@ -86,22 +63,86 @@ void video_refresh_framebuffer(void *data) * true ->高级初始化:增加double buffer的支持 * @return int */ -int video_init(bool level) +int video_reinitialize(bool level) { - init_frame_buffer(level); - if (level) + if (level == false) + init_frame_buffer(); + else { - spin_init(&video_timer_func_add_lock); - // 启用双缓冲后,使能printk滚动动画 - // printk_enable_animation(); - // 初始化第一个屏幕刷新任务 - // struct timer_func_list_t *tmp = (struct timer_func_list_t *)kmalloc(sizeof(struct timer_func_list_t), 0); - // timer_func_init(tmp, &video_refresh_framebuffer, NULL, 10*REFRESH_INTERVAL); - // timer_func_add(tmp); + // 启用屏幕刷新软中断 register_softirq(VIDEO_REFRESH_SIRQ, &video_refresh_framebuffer, NULL); video_refresh_expire_jiffies = cal_next_n_ms_jiffies(10 * REFRESH_INTERVAL); raise_softirq(VIDEO_REFRESH_SIRQ); } + return 0; +} + +/** + * @brief 设置帧缓冲区刷新目标 + * + * @param buf + * @return int + */ +int video_set_refresh_target(struct scm_buffer_info_t *buf) +{ + + unregister_softirq(VIDEO_REFRESH_SIRQ); + int counter = 100; + while ((get_softirq_pending() & (1 << VIDEO_REFRESH_SIRQ)) && counter > 0) + { + --counter; + usleep(1000); + } + video_refresh_target = buf; + register_softirq(VIDEO_REFRESH_SIRQ, &video_refresh_framebuffer, NULL); + raise_softirq(VIDEO_REFRESH_SIRQ); +} + +/** + * @brief 初始化显示驱动 + * + * @return int + */ +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; + + io_mfence(); + // 从multiboot2获取帧缓冲区信息 + int reserved; + multiboot2_iter(multiboot2_get_Framebuffer_info, &__fb_info, &reserved); + io_mfence(); + + // 初始化帧缓冲区信息结构体 + if (__fb_info.framebuffer_type == 2) + { + video_frame_buffer_info.bit_depth = 8; // type=2时,width和height是按照字符数来表示的,因此depth=8 + video_frame_buffer_info.flags |= SCM_BF_TEXT; + } + else + { + video_frame_buffer_info.bit_depth = __fb_info.framebuffer_bpp; + video_frame_buffer_info.flags |= SCM_BF_PIXEL; + } + + video_frame_buffer_info.flags |= SCM_BF_FB; + video_frame_buffer_info.width = __fb_info.framebuffer_width; + video_frame_buffer_info.height = __fb_info.framebuffer_height; + io_mfence(); + + 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; + mm_map_phys_addr(video_frame_buffer_info.vaddr, __fb_info.framebuffer_addr, video_frame_buffer_info.size, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false); + + io_mfence(); + char init_text2[] = "Video driver initialized."; + for (int i = 0; i < sizeof(init_text2) - 1; ++i) + uart_send(COM1, init_text2[i]); + return 0; } \ No newline at end of file diff --git a/kernel/driver/video/video.h b/kernel/driver/video/video.h index aa1b05d0..a20bf26a 100644 --- a/kernel/driver/video/video.h +++ b/kernel/driver/video/video.h @@ -1,15 +1,31 @@ #pragma once #include #include +#include /** - * @brief 初始化显示模块,需先低级初始化才能高级初始化 + * @brief 重新初始化显示驱动,需先低级初始化才能高级初始化 * @param level 初始化等级 * false -> 低级初始化:不使用double buffer * true ->高级初始化:增加double buffer的支持 * @return int */ -int video_init(bool level); +int video_reinitialize(bool level); + +/** + * @brief 初始化显示驱动 + * + * @return int + */ +int video_init(); + +/** + * @brief 设置帧缓冲区刷新目标 + * + * @param buf + * @return int + */ +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; diff --git a/kernel/lib/libUI/screen_manager.c b/kernel/lib/libUI/screen_manager.c index f4933f8c..d836248c 100644 --- a/kernel/lib/libUI/screen_manager.c +++ b/kernel/lib/libUI/screen_manager.c @@ -1 +1,268 @@ -#include "screen_manager.h" \ No newline at end of file +#include "screen_manager.h" +#include +#include +#include +#include +#include +#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 初始化屏幕管理模块 + * + */ +#pragma GCC push_options +#pragma GCC optimize("O0") + +/** + * @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 -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; + + struct Page *p = alloc_pages(ZONE_NORMAL, PAGE_2M_ALIGN(video_frame_buffer_info.size) / PAGE_2M_SIZE, 0); + if (p == NULL) + goto failed; + buf->vaddr = (uint64_t)phys_2_virt(p->addr_phys); + return buf; +failed:; + kfree(buf); + return -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; + + // 释放内存页 + free_pages(Phy_to_2M_Page(virt_2_phys(buf->vaddr)), PAGE_2M_ALIGN(video_frame_buffer_info.size) / PAGE_2M_SIZE); + return 0; +} + +void scm_init() +{ + list_init(&scm_framework_list); + spin_init(&scm_register_lock); + scm_ui_max_id = 0; + __scm_alloc_enabled = false; // 禁用动态申请内存 + __scm_double_buffer_enabled = false; // 禁用双缓冲 +} +/** + * @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) + 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); + 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(&video_frame_buffer_info); + ui->id = scm_ui_max_id++; + spin_unlock(&video_frame_buffer_info); + + 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); + return 0; +} + +/** + * @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() +{ + __scm_alloc_enabled = true; + return 0; +} + +/** + * @brief 允许双缓冲区 + * + * @return int + */ +int scm_enable_double_buffer() +{ + __scm_double_buffer_enabled = true; + if (list_empty(&scm_framework_list)) + return 0; + + // 逐个检查已经注册了的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) + { + struct scm_buffer_info_t *buf = __create_buffer(SCM_BF_DB | SCM_BF_PIXEL); + if ((uint64_t)(buf) == (uint64_t)-ENOMEM) + return -ENOMEM; + if (ptr->ui_ops->change(buf) != 0) + { + __destroy_buffer(buf); + kfree(buf); + } + } + } while (list_next(&ptr->list) != &scm_framework_list); + + // 通知显示驱动,启动双缓冲 + 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; + + return video_set_refresh_target(ui->buf); +} + +#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 1a370f19..35fbe771 100644 --- a/kernel/lib/libUI/screen_manager.h +++ b/kernel/lib/libUI/screen_manager.h @@ -1 +1,112 @@ -#pragma once \ No newline at end of file +#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 0 +#define SCM_FRAMWORK_TYPE_GUI 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); + int (*uninstall)(void *args); + int (*enable)(void *args); + int (*disable)(void *args); + int (*change)(struct scm_buffer_info_t *buf); +}; +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; +}__attribute__((aligned(sizeof(uint64_t)))); + +/** + * @brief 初始化屏幕管理模块 + * + */ +void scm_init(); + +/** + * @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); \ No newline at end of file diff --git a/kernel/main.c b/kernel/main.c index 6cfb5ace..1252104e 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -9,6 +9,7 @@ #include "exception/trap.h" #include "exception/irq.h" #include +#include #include "mm/mm.h" #include "mm/slab.h" #include "process/process.h" @@ -34,12 +35,10 @@ #include #include -#pragma GCC push_options -#pragma GCC optimize("O3") + unsigned int *FR_address = (unsigned int *)0xb8000; //帧缓存区的地址 ul bsp_idt_size, bsp_gdt_size; - // struct Global_Memory_Descriptor memory_management_struct = {{0}, 0}; void test_slab(); @@ -71,12 +70,17 @@ void reload_idt() void system_initialize() { + uart_init(COM1, 115200); + video_init(); + + // scm_init(); // 初始化printk printk_init(8, 16); //#ifdef DEBUG - uart_init(COM1, 115200); //#endif kinfo("Kernel Starting..."); + while (1) + pause(); // 重新加载gdt和idt ul tss_item_addr = (ul)phys_2_virt(0x7c00); @@ -98,9 +102,12 @@ void system_initialize() // 初始化内存管理单元 mm_init(); - + // 内存管理单元初始化完毕后,需要立即重新初始化显示驱动。 + // 原因是,系统启动初期,framebuffer被映射到48M地址处, + // mm初始化完毕后,若不重新初始化显示驱动,将会导致错误的数据写入内存,从而造成其他模块崩溃 // 对显示模块进行低级初始化,不启用double buffer - video_init(false); + video_reinitialize(false); + // =========== 重新设置initial_tss[0]的ist uchar *ptr = (uchar *)kmalloc(STACK_SIZE, 0) + STACK_SIZE; @@ -139,7 +146,6 @@ void system_initialize() smp_init(); io_mfence(); - cpu_init(); ps2_keyboard_init(); // ps2_mouse_init(); @@ -160,7 +166,7 @@ void system_initialize() process_init(); // 对显示模块进行高级初始化,启用double buffer - video_init(true); + video_reinitialize(true); io_mfence(); // fat32_init(); @@ -207,4 +213,3 @@ void ignore_int() while (1) ; } -#pragma GCC pop_options \ No newline at end of file diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c index 15f57652..a3c0c493 100644 --- a/kernel/mm/mm.c +++ b/kernel/mm/mm.c @@ -164,7 +164,6 @@ void mm_init() // ==== 遍历e820数组,完成成员变量初始化工作 === - kdebug("ddd"); for (int i = 0; i < memory_management_struct.len_e820; ++i) { io_mfence(); @@ -229,12 +228,10 @@ void mm_init() ZONE_NORMAL_INDEX = 0; ZONE_UNMAPPED_INDEX = 0; - // kdebug("ZONE_DMA_INDEX=%d\tZONE_NORMAL_INDEX=%d\tZONE_UNMAPPED_INDEX=%d", ZONE_DMA_INDEX, ZONE_NORMAL_INDEX, ZONE_UNMAPPED_INDEX); // 设置内存页管理结构的地址,预留了一段空间,防止内存越界。 memory_management_struct.end_of_struct = (ul)((ul)memory_management_struct.zones_struct + memory_management_struct.zones_struct_len + sizeof(long) * 32) & (~(sizeof(long) - 1)); - // 初始化内存管理单元结构所占的物理页的结构体 ul mms_max_page = (virt_2_phys(memory_management_struct.end_of_struct) >> PAGE_2M_SHIFT); // 内存管理单元所占据的序号最大的物理页 // kdebug("mms_max_page=%ld", mms_max_page); @@ -256,10 +253,10 @@ void mm_init() kinfo("Memory management unit initialize complete!"); flush_tlb(); + // todo: 在这里增加代码,暂时停止视频输出,否则可能会导致图像数据写入slab的区域,从而造成异常 // 初始化slab内存池 slab_init(); page_table_init(); - // init_frame_buffer(); } /** @@ -640,9 +637,8 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s { if (unlikely(*pde_ptr != 0 && user)) { - // kwarn("page already mapped!"); // 如果是用户态可访问的页,则释放当前新获取的物理页 - if (likely(((ul)phys_addr_start + length_mapped) < total_2M_pages)) // 校验是否为内存中的物理页 + if (likely((((ul)phys_addr_start + length_mapped) >> PAGE_2M_SHIFT) < total_2M_pages)) // 校验是否为内存中的物理页 free_pages(Phy_to_2M_Page((ul)phys_addr_start + length_mapped), 1); length_mapped += PAGE_2M_SIZE; continue; @@ -967,15 +963,16 @@ bool mm_check_mapped(ul page_table_phys_addr, uint64_t virt_addr) /** * @brief 检测是否为有效的2M页(物理内存页) - * + * * @param paddr 物理地址 * @return int8_t 是 -> 1 * 否 -> 0 */ int8_t mm_is_2M_page(uint64_t paddr) { - if(likely((paddr >> PAGE_2M_SHIFT)> PAGE_2M_SHIFT) < total_2M_pages)) return 1; - else return 0; + else + return 0; } // #pragma GCC pop_options \ No newline at end of file