使用内核线程来刷新屏幕 (#57)

* 修改了test-idr的错误

* new: 修复切换双缓冲的时候的卡顿问题

Signed-off-by: guanjinquan <1666320330@qq.com>
Co-authored-by: guanjinquan <1666320330@qq.com>
Co-authored-by: fslongjin <longjin@RinGoTek.cn>
This commit is contained in:
login 2022-10-12 18:45:58 +08:00 committed by GitHub
parent 1b0c901ab2
commit efa38a7d5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 152 additions and 87 deletions

View File

@ -144,7 +144,8 @@
"ktest_utils.h": "c",
"kthread.h": "c",
"lockref.h": "c",
"compiler_attributes.h": "c"
"compiler_attributes.h": "c",
"timer.h": "c"
},
"C_Cpp.errorSquiggles": "Enabled",
"esbonio.sphinx.confDir": ""

View File

@ -439,7 +439,8 @@ void pci_init()
{
if (ptr->Status & 0x10)
{
kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\tcap_pointer=%#010lx\tbar5=%#010lx", i, ptr->Class_code, ptr->SubClass, ptr->Status, ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer, ((struct pci_device_structure_general_device_t *)ptr)->BAR5);
kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\tcap_pointer=%#010lx\tbar5=%#010lx, vendor=%#08x, device id=%#08x", i, ptr->Class_code, ptr->SubClass, ptr->Status, ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer, ((struct pci_device_structure_general_device_t *)ptr)->BAR5,
ptr->Vendor_ID, ptr->Device_ID);
uint32_t tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer);
}
else

View File

@ -1,17 +1,17 @@
#include "video.h"
#include <mm/mm.h>
#include <common/printk.h>
#include <driver/multiboot2/multiboot2.h>
#include <time/timer.h>
#include <common/kprint.h>
#include <common/kthread.h>
#include <common/printk.h>
#include <common/spinlock.h>
#include <common/time.h>
#include <driver/multiboot2/multiboot2.h>
#include <driver/uart/uart.h>
#include <exception/softirq.h>
#include <mm/mm.h>
#include <mm/slab.h>
#include <common/spinlock.h>
#include <exception/softirq.h>
#include <driver/uart/uart.h>
#include <common/time.h>
#include <process/process.h>
#include <sched/sched.h>
#include <time/timer.h>
uint64_t video_refresh_expire_jiffies = 0;
uint64_t video_last_refresh_pid = -1;
@ -19,10 +19,11 @@ 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 process_control_block *video_daemon_pcb = NULL;
static spinlock_t daemon_refresh_lock;
#define REFRESH_INTERVAL 15UL // 启动刷新帧缓冲区任务的时间间隔
/**
* @brief VBE帧缓存区的地址重新映射
* SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE处
@ -37,22 +38,53 @@ void init_frame_buffer()
int reserved;
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);
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!");
}
/**
* @brief
*
* @brief video守护进程,
* @param unused
* @return int
*/
int video_refresh_daemon(void *unused)
{
// 初始化锁, 这个锁只会在daemon中使用
spin_init(&daemon_refresh_lock);
for (;;)
{
if (clock() >= video_refresh_expire_jiffies)
{
video_refresh_expire_jiffies = cal_next_n_ms_jiffies(REFRESH_INTERVAL << 1);
if (likely(video_refresh_target != NULL))
{
spin_lock(&daemon_refresh_lock);
memcpy((void *)video_frame_buffer_info.vaddr, (void *)video_refresh_target->vaddr,
video_refresh_target->size);
spin_unlock(&daemon_refresh_lock);
}
}
video_daemon_pcb->flags &= ~PROC_RUNNING;
sched();
}
return 0;
}
/**
* @brief video的守护进程
*/
void video_refresh_framebuffer(void *data)
{
video_refresh_expire_jiffies = cal_next_n_ms_jiffies(REFRESH_INTERVAL << 1);
if (unlikely(video_refresh_target == NULL))
if (unlikely(video_daemon_pcb == NULL))
return;
memcpy((void *)video_frame_buffer_info.vaddr, (void *)video_refresh_target->vaddr, video_refresh_target->size);
process_wakeup(video_daemon_pcb);
}
/**
@ -62,17 +94,22 @@ void video_refresh_framebuffer(void *data)
* true ->double buffer的支持
* @return int
*/
int video_reinitialize(bool level)
int video_reinitialize(bool level) // 这个函数会在main.c调用, 保证 video_init() 先被调用
{
if (level == false)
init_frame_buffer();
else
{
// 计算开始时间
video_refresh_expire_jiffies = cal_next_n_ms_jiffies(10 * REFRESH_INTERVAL);
// 创建video守护进程
video_daemon_pcb = kthread_run(&video_refresh_daemon, NULL, CLONE_FS | CLONE_SIGNAL);
video_daemon_pcb->virtual_runtime = 0; // 特殊情况, 最高优先级, 以后再改
// 启用屏幕刷新软中断
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;
@ -88,12 +125,16 @@ 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);
}
// todo: 在completion实现后在这里等待其他刷新任务完成再进行下一步。
// int counter = 100;
// while ((get_softirq_pending() & (1 << VIDEO_REFRESH_SIRQ)) && counter > 0)
// {
// --counter;
// usleep(1000);
// }
// kdebug("buf = %#018lx", buf);
video_refresh_target = buf;
register_softirq(VIDEO_REFRESH_SIRQ, &video_refresh_framebuffer, NULL);
raise_softirq(VIDEO_REFRESH_SIRQ);
@ -134,14 +175,17 @@ int video_init()
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.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);
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;
}

View File

@ -33,7 +33,7 @@ static long ktest_idr_case0(uint64_t arg0, uint64_t arg1)
idr_init(&k_idr);
assert(k_idr.id_free_cnt == 0);
assert(idr_pre_get(&k_idr, 0) == 1);
assert(idr_pre_get(&k_idr, 0) == 0);
assert(k_idr.id_free_cnt == IDR_FREE_MAX);
for (int i = 1; i < 64; i++)

View File

@ -1,12 +1,12 @@
#include "screen_manager.h"
#include <common/string.h>
#include <driver/multiboot2/multiboot2.h>
#include <common/kprint.h>
#include <common/spinlock.h>
#include <mm/mm.h>
#include <mm/slab.h>
#include <common/string.h>
#include <driver/multiboot2/multiboot2.h>
#include <driver/uart/uart.h>
#include <driver/video/video.h>
#include <mm/mm.h>
#include <mm/slab.h>
extern struct scm_buffer_info_t video_frame_buffer_info;
static struct List scm_framework_list;
@ -234,35 +234,43 @@ int scm_enable_alloc()
*/
int scm_enable_double_buffer()
{
if (__scm_double_buffer_enabled == true)
if (__scm_double_buffer_enabled == true) // 已经开启了双缓冲区了, 直接退出
return 0;
__scm_double_buffer_enabled = true;
if (list_empty(&scm_framework_list))
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)
{
uart_send_str(COM1, "##init double buffer##");
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;
uart_send_str(COM1, "##to change double buffer##");
if (ptr->ui_ops->change(buf) != 0)
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);
} while (list_next(&ptr->list) != &scm_framework_list); // 枚举链表的每一个ui框架
// 设置定时刷新的对象
video_set_refresh_target(__current_framework->buf);
// 通知显示驱动,启动双缓冲
video_reinitialize(true);
uart_send_str(COM1, "##initialized double buffer##");
uart_send_str(COM1, "##initialized double buffer##\n");
return 0;
}

View File

@ -1,11 +1,11 @@
#include "textui.h"
#include "screen_manager.h"
#include "driver/uart/uart.h"
#include <common/string.h>
#include <common/printk.h>
#include "screen_manager.h"
#include <common/atomic.h>
#include <common/errno.h>
#include <common/printk.h>
#include <common/string.h>
struct scm_ui_framework_t textui_framework;
static spinlock_t __window_id_lock = {1};
@ -19,6 +19,7 @@ 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;
/**
* @brief window对象
@ -29,7 +30,8 @@ static struct List __windows_list;
* @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)
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);
@ -56,12 +58,12 @@ static int __textui_init_window(struct textui_window_t *window, uint8_t flags, u
* @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; \
#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)
@ -78,7 +80,7 @@ int textui_uninstall_handler(void *args)
int textui_enable_handler(void *args)
{
uart_send_str(COM1, "textui_enable_handler");
uart_send_str(COM1, "textui_enable_handler\n");
return 0;
}
@ -91,16 +93,16 @@ 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,
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,
};
/**
@ -166,7 +168,8 @@ static int __textui_new_line(struct textui_window_t *window, uint16_t vline_id)
* @param character
* @return int
*/
static int __textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor, uint32_t BKcolor)
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)) // 启用彩色字符
{
@ -246,7 +249,8 @@ int textui_putchar_window(struct textui_window_t *window, uint16_t character, ui
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);
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;
@ -295,6 +299,8 @@ int textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor)
*/
int textui_init()
{
spin_init(&change_lock);
spin_init(&__window_id_lock);
__window_max_id = 0;
list_init(&__windows_list);

View File

@ -165,7 +165,7 @@ void system_initialize()
process_init();
// 启用double buffer
scm_enable_double_buffer();
// scm_enable_double_buffer(); // 因为时序问题, 该函数调用被移到 initial_kernel_thread
io_mfence();
// fat32_init();

View File

@ -1,29 +1,29 @@
#include "process.h"
#include <common/printk.h>
#include <common/kprint.h>
#include <common/stdio.h>
#include <common/string.h>
#include <common/compiler.h>
#include <common/elf.h>
#include <common/kprint.h>
#include <common/kthread.h>
#include <common/time.h>
#include <common/printk.h>
#include <common/spinlock.h>
#include <common/stdio.h>
#include <common/string.h>
#include <common/sys/wait.h>
#include <driver/video/video.h>
#include <common/time.h>
#include <common/unistd.h>
#include <debug/bug.h>
#include <debug/traceback/traceback.h>
#include <driver/disk/ahci/ahci.h>
#include <driver/usb/usb.h>
#include <driver/video/video.h>
#include <exception/gate.h>
#include <filesystem/fat32/fat32.h>
#include <filesystem/devfs/devfs.h>
#include <filesystem/fat32/fat32.h>
#include <filesystem/rootfs/rootfs.h>
#include <mm/slab.h>
#include <common/spinlock.h>
#include <sched/sched.h>
#include <syscall/syscall.h>
#include <syscall/syscall_num.h>
#include <sched/sched.h>
#include <common/unistd.h>
#include <debug/traceback/traceback.h>
#include <debug/bug.h>
#include <driver/disk/ahci/ahci.h>
#include <ktest/ktest.h>
@ -372,7 +372,7 @@ ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[])
// 独立的地址空间才能使新程序正常运行
if (current_pcb->flags & PF_VFORK)
{
kdebug("proc:%d creating new mem space", current_pcb->pid);
// kdebug("proc:%d creating new mem space", current_pcb->pid);
// 分配新的内存空间分布结构体
struct mm_struct *new_mms = (struct mm_struct *)kmalloc(sizeof(struct mm_struct), 0);
memset(new_mms, 0, sizeof(struct mm_struct));
@ -479,7 +479,9 @@ exec_failed:;
#pragma GCC optimize("O0")
ul initial_kernel_thread(ul arg)
{
// kinfo("initial proc running...\targ:%#018lx", arg);
kinfo("initial proc running...\targ:%#018lx", arg);
scm_enable_double_buffer();
ahci_init();
fat32_init();
@ -582,7 +584,7 @@ ul process_do_exit(ul code)
* @return int
*/
pid_t kernel_thread(int (*fn)(void*), void* arg, unsigned long flags)
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
struct pt_regs regs;
barrier();
@ -794,13 +796,16 @@ struct process_control_block *process_get_pcb(long pid)
*/
int process_wakeup(struct process_control_block *pcb)
{
// kdebug("pcb pid = %#018lx", pcb->pid);
BUG_ON(pcb == NULL);
if (pcb == current_pcb || pcb == NULL)
return -EINVAL;
// 如果pcb正在调度队列中则不重复加入调度队列
if (pcb->state == PROC_RUNNING)
if (pcb->state & PROC_RUNNING)
return 0;
pcb->state = PROC_RUNNING;
pcb->state |= PROC_RUNNING;
sched_enqueue(pcb);
return 0;
}
@ -812,7 +817,7 @@ int process_wakeup(struct process_control_block *pcb)
*/
int process_wakeup_immediately(struct process_control_block *pcb)
{
if (pcb->state == PROC_RUNNING)
if (pcb->state & PROC_RUNNING)
return 0;
int retval = process_wakeup(pcb);
if (retval != 0)

View File

@ -69,10 +69,10 @@ void sched_cfs()
current_pcb->flags &= ~PF_NEED_SCHED;
struct process_control_block *proc = sched_cfs_dequeue();
// kdebug("sched_cfs_ready_queue[proc_current_cpu_id].count = %d", sched_cfs_ready_queue[proc_current_cpu_id].count);
if (current_pcb->virtual_runtime >= proc->virtual_runtime || current_pcb->state != PROC_RUNNING) // 当前进程运行时间大于了下一进程的运行时间,进行切换
if (current_pcb->virtual_runtime >= proc->virtual_runtime || !(current_pcb->state & PROC_RUNNING)) // 当前进程运行时间大于了下一进程的运行时间,进行切换
{
if (current_pcb->state == PROC_RUNNING) // 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理
if (current_pcb->state & PROC_RUNNING) // 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理
sched_cfs_enqueue(current_pcb);
// kdebug("proc->pid=%d, count=%d", proc->pid, sched_cfs_ready_queue[proc_current_cpu_id].count);
if (sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies <= 0)

View File

@ -7,9 +7,9 @@
uint64_t volatile timer_jiffies = 0; // 系统时钟计数
// 计算接下来n毫秒对应的系统时间片
#define cal_next_n_ms_jiffies(expire_ms) (timer_jiffies + 1000*expire_ms)
#define cal_next_n_ms_jiffies(expire_ms) (timer_jiffies + 1000 * (expire_ms))
// 计算接下来n微秒对应的系统时间片
#define cal_next_n_us_jiffies(expire_us) (timer_jiffies + expire_us)
#define cal_next_n_us_jiffies(expire_us) (timer_jiffies + (expire_us))
void timer_init();
@ -62,5 +62,4 @@ void timer_func_add(struct timer_func_list_t *timer_func);
*/
void timer_func_del(struct timer_func_list_t *timer_func);
uint64_t clock();

1
run.sh
View File

@ -174,6 +174,7 @@ if [ $flag_can_run -eq 1 ]; then
-drive id=disk,file=bin/disk.img,if=none \
-device ahci,id=ahci \
-device ide-hd,drive=disk,bus=ahci.0 \
-net nic,model=virtio \
-usb \
-device qemu-xhci,id=xhci,p2=8,p3=4 \
-machine accel=${qemu_accel}