fslongjin 2 жил өмнө
parent
commit
464837eb1a

+ 27 - 18
kernel/common/printk.c

@@ -8,12 +8,14 @@
 #include "../process/spinlock.h"
 
 #include <driver/uart/uart.h>
+#include <driver/video/video.h>
 
 //#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;
 }

+ 13 - 7
kernel/common/printk.h

@@ -35,7 +35,7 @@
 //#include "linkage.h"
 #include <stdarg.h>
 
-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();
+uint* get_pos_VBE_FB_addr();
+
+/**
+ * @brief 使能滚动动画
+ * 
+ */
+void printk_enable_animation();
+/**
+ * @brief 禁用滚动动画
+ * 
+ */
+void printk_disable_animation();

+ 11 - 1
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);

+ 2 - 0
kernel/driver/timers/HPET/HPET.h

@@ -5,4 +5,6 @@
 #include<driver/timers/rtc/rtc.h>
 
 #define E_HPET_INIT_FAILED 1
+
+#define HPET0_INTERVAL 5    // HPET0定时器的中断间隔为5ms
 int HPET_init();

+ 7 - 7
kernel/driver/timers/timer.c

@@ -2,6 +2,7 @@
 #include <common/kprint.h>
 #include <exception/softirq.h>
 #include <mm/slab.h>
+#include <driver/timers/HPET/HPET.h>
 
 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));
-
-
 }
 
 /**

+ 2 - 2
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 将定时功能添加到列表中

+ 90 - 4
kernel/driver/video/video.c

@@ -1,11 +1,97 @@
 #include "video.h"
+#include <mm/mm.h>
+#include <common/printk.h>
+#include <driver/multiboot2/multiboot2.h>
+#include <driver/timers/timer.h>
+#include <common/kprint.h>
+#include <mm/mm.h>
+#include <mm/slab.h>
+
+#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 VBE帧缓存区的地址重新映射
+ * 将帧缓存区映射到地址0xffff800003000000处
+ */
+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 初始化显示模块
- * 
- * @return int 
+ * @brief 初始化显示模块,需先低级初始化才能高级初始化
+ * @param level 初始化等级
+ * false -> 低级初始化:不使用double buffer
+ * true ->高级初始化:增加double buffer的支持
+ * @return int
  */
-int video_init()
+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);
 
+    }
 }

+ 8 - 5
kernel/driver/video/video.h

@@ -1,8 +1,11 @@
 #pragma once
-
+#include <common/glib.h>
+#include <stdbool.h>
 /**
- * @brief 初始化显示模块
- * 
- * @return int 
+ * @brief 初始化显示模块,需先低级初始化才能高级初始化
+ * @param level 初始化等级
+ * false -> 低级初始化:不使用double buffer
+ * true ->高级初始化:增加double buffer的支持
+ * @return int
  */
-int video_init();
+int video_init(bool level);

+ 7 - 0
kernel/main.c

@@ -30,6 +30,7 @@
 #include <driver/timers/HPET/HPET.h>
 #include <driver/timers/timer.h>
 #include <driver/uart/uart.h>
+#include <driver/video/video.h>
 
 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();
     // 系统初始化到此结束,剩下的初始化功能应当放在初始内核线程中执行

+ 1 - 17
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 将物理地址映射到页表的函数

+ 0 - 6
kernel/mm/mm.h

@@ -348,12 +348,6 @@ typedef struct
  */
 void page_table_init();
 
-/**
- * @brief VBE帧缓存区的地址重新映射
- * 将帧缓存区映射到地址0xffff800008000000处
- */
-void init_frame_buffer();
-
 /**
  * @brief 将物理地址映射到页表的函数
  *