diff --git a/kernel/common/printk.c b/kernel/common/printk.c index 83933af8..073ffff2 100644 --- a/kernel/common/printk.c +++ b/kernel/common/printk.c @@ -8,12 +8,14 @@ #include "../process/spinlock.h" #include +#include //#include "linkage.h" -struct screen_info pos; -ul VBE_FB_phys_addr; // 由bootloader传来的帧缓存区的物理地址 +struct printk_screen_info pos; +extern ul VBE_FB_phys_addr; // 由bootloader传来的帧缓存区的物理地址 static spinlock_t printk_lock; +static bool sw_show_scroll_animation = false; // 显示换行动画的开关 int calculate_max_charNum(int len, int size) { @@ -78,7 +80,8 @@ int printk_init(const int char_size_x, const int char_size_y) cls(); kdebug("width=%d\theight=%d", pos.width, pos.height); - + // 由于此时系统并未启用双缓冲,因此关闭滚动动画 + printk_disable_animation(); return 0; } @@ -128,7 +131,7 @@ void auto_newline() #endif pos.y = pos.max_y; int lines_to_scroll = 1; - scroll(true, lines_to_scroll * pos.char_size_y, false); + scroll(true, lines_to_scroll * pos.char_size_y, sw_show_scroll_animation); pos.y -= (lines_to_scroll - 1); } } @@ -674,8 +677,7 @@ static void putchar(uint *fb, int Xsize, int x, int y, unsigned int FRcolor, uns int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ...) { - - uint64_t rflags = 0; // 加锁后rflags存储到这里 + uint64_t rflags = 0; // 加锁后rflags存储到这里 spin_lock_irqsave(&printk_lock, rflags); va_list args; @@ -768,7 +770,6 @@ int do_scroll(bool direction, int pixels) */ // @todo: 修复用户态触发键盘中断时产生#UD错误 -// @todo:采用双缓冲区 int scroll(bool direction, int pixels, bool animation) { // 暂时不支持反方向滚动 @@ -788,7 +789,7 @@ int scroll(bool direction, int pixels, bool animation) if (pixels > 10) steps = 5; else - steps = pixels % 5; + steps = pixels % 10; int half_steps = steps / 2; // 计算加速度 @@ -834,7 +835,7 @@ int scroll(bool direction, int pixels, bool animation) do_scroll(direction, delta_x); } } - + return 0; } @@ -850,15 +851,6 @@ int cls() return 0; } -/** - * @brief 获取VBE帧缓存区的物理地址 - * - */ -ul get_VBE_FB_phys_addr() -{ - return VBE_FB_phys_addr; -} - /** * @brief 获取VBE帧缓冲区长度 */ @@ -879,4 +871,21 @@ void set_pos_VBE_FB_addr(uint *virt_addr) uint *get_pos_VBE_FB_addr() { return pos.FB_address; +} + +/** + * @brief 使能滚动动画 + * + */ +void printk_enable_animation() +{ + sw_show_scroll_animation = true; +} +/** + * @brief 禁用滚动动画 + * + */ +void printk_disable_animation() +{ + sw_show_scroll_animation = false; } \ No newline at end of file diff --git a/kernel/common/printk.h b/kernel/common/printk.h index 6694e7ce..d790e949 100644 --- a/kernel/common/printk.h +++ b/kernel/common/printk.h @@ -35,7 +35,7 @@ //#include "linkage.h" #include -struct screen_info +struct printk_screen_info { int width, height; //屏幕大小 @@ -132,11 +132,6 @@ int scroll(bool direction, int pixels, bool animation); */ int cls(); -/** - * @brief 获取VBE帧缓存区的物理地址 - * - */ -ul get_VBE_FB_phys_addr(); /** * @brief 获取VBE帧缓冲区长度 @@ -150,4 +145,15 @@ ul get_VBE_FB_length(); */ void set_pos_VBE_FB_addr(uint* virt_addr); -uint* get_pos_VBE_FB_addr(); \ No newline at end of file +uint* get_pos_VBE_FB_addr(); + +/** + * @brief 使能滚动动画 + * + */ +void printk_enable_animation(); +/** + * @brief 禁用滚动动画 + * + */ +void printk_disable_animation(); diff --git a/kernel/driver/timers/HPET/HPET.c b/kernel/driver/timers/HPET/HPET.c index b8d094ce..411d99e8 100644 --- a/kernel/driver/timers/HPET/HPET.c +++ b/kernel/driver/timers/HPET/HPET.c @@ -146,11 +146,21 @@ int HPET_init() // 使用I/O APIC 的IRQ2接收hpet定时器0的中断 apic_make_rte_entry(&entry, 34, IO_APIC_FIXED, DEST_PHYSICAL, IDLE, POLARITY_HIGH, IRR_RESET, EDGE_TRIGGER, MASKED, 0); + // 计算HPET0间隔多少个时钟周期触发一次中断 + uint64_t clks_to_intr = 0.001 * HPET0_INTERVAL * HPET_freq; + if (clks_to_intr <= 0 || clks_to_intr > (HPET_freq * 8)) + { + kBUG("HPET0: Numof clocks to generate interrupt is INVALID! value=%lld", clks_to_intr); + while (1) + hlt(); + } + *(uint64_t *)(HPET_REG_BASE + MAIN_CNT) = 0; io_mfence(); *(uint64_t *)(HPET_REG_BASE + TIM0_CONF) = 0x004c; // 设置定时器0为周期定时,边沿触发,投递到IO APIC的2号引脚(这里有点绕,写的是8259的引脚号,但是因为禁用了8259,因此会被路由到IO APIC的2号引脚) io_mfence(); - *(uint64_t *)(HPET_REG_BASE + TIM0_COMP) = HPET_freq; // 1s触发一次中断 + *(uint64_t *)(HPET_REG_BASE + TIM0_COMP) = clks_to_intr; // 5ms触发一次中断 + //*(uint64_t *)(HPET_REG_BASE + TIM0_COMP) = HPET_freq; // 1s触发一次中断 io_mfence(); rtc_get_cmos_time(&rtc_now); diff --git a/kernel/driver/timers/HPET/HPET.h b/kernel/driver/timers/HPET/HPET.h index 3217f3ae..4d41e25b 100644 --- a/kernel/driver/timers/HPET/HPET.h +++ b/kernel/driver/timers/HPET/HPET.h @@ -5,4 +5,6 @@ #include #define E_HPET_INIT_FAILED 1 + +#define HPET0_INTERVAL 5 // HPET0定时器的中断间隔为5ms int HPET_init(); \ No newline at end of file diff --git a/kernel/driver/timers/timer.c b/kernel/driver/timers/timer.c index 22998163..cef1c322 100644 --- a/kernel/driver/timers/timer.c +++ b/kernel/driver/timers/timer.c @@ -2,6 +2,7 @@ #include #include #include +#include void test_timer() { @@ -25,7 +26,7 @@ void do_timer_softirq(void *data) { struct timer_func_list_t *tmp = container_of(list_next(&timer_func_head.list), struct timer_func_list_t, list); - + while ((!list_empty(&timer_func_head.list)) && (tmp->expire_jiffies <= timer_jiffies)) { timer_func_del(tmp); @@ -34,7 +35,7 @@ void do_timer_softirq(void *data) tmp = container_of(list_next(&timer_func_head.list), struct timer_func_list_t, list); } - printk_color(ORANGE, BLACK, "(HPET%ld)", timer_jiffies); + // printk_color(ORANGE, BLACK, "(HPET%ld)", timer_jiffies); } /** @@ -42,14 +43,15 @@ void do_timer_softirq(void *data) * * @param timer_func 队列结构体 * @param func 定时功能处理函数 - * @param expire_jiffies 定时时长 + * @param data 传输的数据 + * @param expire_ms 定时时长(单位:ms) */ -void timer_func_init(struct timer_func_list_t *timer_func, void (*func)(void *data), void *data, uint64_t expire_jiffies) +void timer_func_init(struct timer_func_list_t *timer_func, void (*func)(void *data), void *data, uint64_t expire_ms) { list_init(&timer_func->list); timer_func->func = func; timer_func->data = data, - timer_func->expire_jiffies = timer_jiffies + expire_jiffies; + timer_func->expire_jiffies = timer_jiffies + expire_ms / 5 + expire_ms % HPET0_INTERVAL ? 1 : 0; // 设置过期的时间片 } /** @@ -66,8 +68,6 @@ void timer_func_add(struct timer_func_list_t *timer_func) tmp = container_of(list_next(&tmp->list), struct timer_func_list_t, list); list_add(&tmp->list, &(timer_func->list)); - - } /** diff --git a/kernel/driver/timers/timer.h b/kernel/driver/timers/timer.h index 3c57a7e3..140d450e 100644 --- a/kernel/driver/timers/timer.h +++ b/kernel/driver/timers/timer.h @@ -28,9 +28,9 @@ struct timer_func_list_t * @param timer_func 队列结构体 * @param func 定时功能处理函数 * @param data 传输的数据 - * @param expire_jiffies 定时时长 + * @param expire_ms 定时时长(单位:ms) */ -void timer_func_init(struct timer_func_list_t * timer_func, void (*func)(void*data), void*data,uint64_t expire_jiffies); +void timer_func_init(struct timer_func_list_t * timer_func, void (*func)(void*data), void*data,uint64_t expire_ms); /** * @brief 将定时功能添加到列表中 diff --git a/kernel/driver/video/video.c b/kernel/driver/video/video.c index 2bb78601..5232df64 100644 --- a/kernel/driver/video/video.c +++ b/kernel/driver/video/video.c @@ -1,11 +1,97 @@ #include "video.h" +#include +#include +#include +#include +#include +#include +#include + +#define REFRESH_INTERVAL 15 // 启动刷新帧缓冲区任务的时间间隔 + +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 初始化显示模块 - * - * @return int + * @brief VBE帧缓存区的地址重新映射 + * 将帧缓存区映射到地址0xffff800003000000处 */ -int video_init() +void init_frame_buffer(bool level) { + 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; + + 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); + 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); + + // 将原有的数据拷贝到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); + } + + flush_tlb(); + kinfo("VBE frame buffer successfully Re-mapped!"); +} + +/** + * @brief 刷新帧缓冲区 + * + */ +static void video_refresh_framebuffer() +{ + memcpy((void *)sc_info.fb_vaddr, (void *)sc_info.double_fb_vaddr, (sc_info.length << 2)); + // 新增下一个刷新定时任务 + 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, REFRESH_INTERVAL); + timer_func_add(tmp); +} + +/** + * @brief 初始化显示模块,需先低级初始化才能高级初始化 + * @param level 初始化等级 + * false -> 低级初始化:不使用double buffer + * true ->高级初始化:增加double buffer的支持 + * @return int + */ +int video_init(bool level) +{ + init_frame_buffer(level); + if (level) + { + // 启用双缓冲后,使能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, REFRESH_INTERVAL); + timer_func_add(tmp); + + } } \ No newline at end of file diff --git a/kernel/driver/video/video.h b/kernel/driver/video/video.h index 3b875fed..f1c6b38c 100644 --- a/kernel/driver/video/video.h +++ b/kernel/driver/video/video.h @@ -1,8 +1,11 @@ #pragma once - +#include +#include /** - * @brief 初始化显示模块 - * - * @return int + * @brief 初始化显示模块,需先低级初始化才能高级初始化 + * @param level 初始化等级 + * false -> 低级初始化:不使用double buffer + * true ->高级初始化:增加double buffer的支持 + * @return int */ -int video_init(); \ No newline at end of file +int video_init(bool level); \ No newline at end of file diff --git a/kernel/main.c b/kernel/main.c index b17ace39..467f3d76 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -30,6 +30,7 @@ #include #include #include +#include unsigned int *FR_address = (unsigned int *)0xb8000; //帧缓存区的地址 ul bsp_idt_size, bsp_gdt_size; @@ -112,6 +113,10 @@ void system_initialize() // 初始化内存管理单元 mm_init(); + // 对显示模块进行低级初始化,不启用double buffer + video_init(false); + + // =========== 重新设置initial_tss[0]的ist uchar *ptr = (uchar *)kmalloc(STACK_SIZE, 0) + STACK_SIZE; ((struct process_control_block *)(ptr - STACK_SIZE))->cpu_id = 0; @@ -155,6 +160,8 @@ void system_initialize() // process_init(); process_init(); + // 对显示模块进行高级初始化,启用double buffer + video_init(true); HPET_init(); // fat32_init(); // 系统初始化到此结束,剩下的初始化功能应当放在初始内核线程中执行 diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c index 493043fa..5fe9ec18 100644 --- a/kernel/mm/mm.c +++ b/kernel/mm/mm.c @@ -237,7 +237,7 @@ void mm_init() // 初始化slab内存池 slab_init(); page_table_init(); - init_frame_buffer(); + // init_frame_buffer(); } /** @@ -484,23 +484,7 @@ void page_table_init() kinfo("Page table Initialized."); } -/** - * @brief VBE帧缓存区的地址重新映射 - * 将帧缓存区映射到地址0xffff800003000000处 - */ -void init_frame_buffer() -{ - kinfo("Re-mapping VBE frame buffer..."); - uint64_t global_CR3 = (uint64_t)get_CR3(); - ul fb_virt_addr = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + FRAME_BUFFER_MAPPING_OFFSET; - ul fb_phys_addr = get_VBE_FB_phys_addr(); - // mm_map_phys_addr(fb_virt_addr, fb_phys_addr, get_VBE_FB_length(), PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD); - mm_map_proc_page_table(global_CR3, true, fb_virt_addr, fb_phys_addr, get_VBE_FB_length() << 2, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false); - set_pos_VBE_FB_addr((uint *)fb_virt_addr); - flush_tlb(); - kinfo("VBE frame buffer successfully Re-mapped!"); -} /** * @brief 将物理地址映射到页表的函数 diff --git a/kernel/mm/mm.h b/kernel/mm/mm.h index 5a9e59d3..a7435477 100644 --- a/kernel/mm/mm.h +++ b/kernel/mm/mm.h @@ -348,12 +348,6 @@ typedef struct */ void page_table_init(); -/** - * @brief VBE帧缓存区的地址重新映射 - * 将帧缓存区映射到地址0xffff800008000000处 - */ -void init_frame_buffer(); - /** * @brief 将物理地址映射到页表的函数 *