diff --git a/.vscode/settings.json b/.vscode/settings.json index 42f2cf4e..821a1f3c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -98,7 +98,8 @@ "ipi.h": "c", "arch.h": "c", "elf.h": "c", - "stdio.h": "c" + "stdio.h": "c", + "wait_queue.h": "c" }, "C_Cpp.errorSquiggles": "Enabled", "esbonio.sphinx.confDir": "" diff --git a/kernel/Makefile b/kernel/Makefile index 04790e51..9e96b483 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -18,7 +18,7 @@ LD_LIST := head.o OBJ_LIST := head.o -kernel_subdirs := common driver +kernel_subdirs := common driver process @@ -33,9 +33,7 @@ entry.o: exception/entry.S gcc -E exception/entry.S > exception/entry.s as $(ASFLAGS) -o exception/entry.o exception/entry.s -procs.o: process/proc.S - gcc -E process/proc.S > process/proc.s - as $(ASFLAGS) -o process/procs.o process/proc.s + @@ -62,8 +60,6 @@ mm.o: mm/mm.c slab.o: mm/slab.c gcc $(CFLAGS) -c mm/slab.c -o mm/slab.o -process.o: process/process.c - gcc $(CFLAGS) -c process/process.c -o process/process.o sched.o: sched/sched.c gcc $(CFLAGS) -c sched/sched.c -o sched/sched.o @@ -150,15 +146,15 @@ uart.o: driver/uart/uart.c all: kernel - ld -b elf64-x86-64 -z muldefs -o kernel head.o main.o $(shell find . -name "*.o") -T link.lds + ld -b elf64-x86-64 -z muldefs -o kernel head.o main.o $(shell find . -name "*.o") -T link.lds objcopy -I elf64-x86-64 -O elf64-x86-64 -R ".comment" -R ".eh_frame" kernel ../bin/kernel/kernel.elf -kernel: head.o entry.o procs.o main.o printk.o trap.o mm.o slab.o irq.o pic.o process.o sched.o syscall.o multiboot2.o cpu.o acpi.o ps2_keyboard.o ps2_mouse.o ata.o pci.o ahci.o smp.o apu_boot.o rtc.o HPET.o softirq.o timer.o fat32.o MBR.o VFS.o $(OBJ_LIST) +kernel: head.o entry.o main.o printk.o trap.o mm.o slab.o irq.o pic.o sched.o syscall.o multiboot2.o cpu.o acpi.o ps2_keyboard.o ps2_mouse.o ata.o pci.o ahci.o smp.o apu_boot.o rtc.o HPET.o softirq.o timer.o fat32.o MBR.o VFS.o $(OBJ_LIST) @list='$(kernel_subdirs)'; for subdir in $$list; do \ echo "make all in $$subdir";\ cd $$subdir;\ - $(MAKE) all CFLAGS="$(CFLAGS)";\ + $(MAKE) all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)";\ cd ..;\ done diff --git a/kernel/common/glib.h b/kernel/common/glib.h index 4334a527..a31ae8a2 100644 --- a/kernel/common/glib.h +++ b/kernel/common/glib.h @@ -11,8 +11,6 @@ #include #include - - #define sti() __asm__ __volatile__("sti\n\t" :: \ : "memory") //开启外部中断 #define cli() __asm__ __volatile__("cli\n\t" :: \ @@ -105,24 +103,24 @@ static inline void list_add(struct List *entry, struct List *node) entry->next = node; } +/** + * @brief 将node添加到给定的list的结尾(也就是当前节点的前面) + * @param entry 列表的入口 + * @param node 待添加的节点 + */ static inline void list_append(struct List *entry, struct List *node) { - /** - * @brief 将node添加到给定的list的结尾(也就是当前节点的前面) - * @param entry 列表的入口 - * @param node 待添加的节点 - */ struct List *tail = entry->prev; list_add(tail, node); } +/** + * @brief 从列表中删除节点 + * @param entry 待删除的节点 + */ static inline void list_del(struct List *entry) { - /** - * @brief 从列表中删除节点 - * @param entry 待删除的节点 - */ entry->next->prev = entry->prev; entry->prev->next = entry->next; diff --git a/kernel/driver/disk/ahci/ahci.c b/kernel/driver/disk/ahci/ahci.c index 82514149..c657dc09 100644 --- a/kernel/driver/disk/ahci/ahci.c +++ b/kernel/driver/disk/ahci/ahci.c @@ -465,7 +465,8 @@ static struct ahci_request_packet_t *ahci_make_request(long cmd, uint64_t base_a void ahci_end_request() { ahci_req_queue.in_service->wait_queue.pcb->state = PROC_RUNNING; - ahci_req_queue.in_service->wait_queue.pcb->flags |= PF_NEED_SCHED; + // ahci_req_queue.in_service->wait_queue.pcb->flags |= PF_NEED_SCHED; + // current_pcb->flags |= PF_NEED_SCHED; kfree((uint64_t *)ahci_req_queue.in_service); ahci_req_queue.in_service = NULL; diff --git a/kernel/driver/keyboard/ps2_keyboard.c b/kernel/driver/keyboard/ps2_keyboard.c index fd0ed4e5..05c61dc9 100644 --- a/kernel/driver/keyboard/ps2_keyboard.c +++ b/kernel/driver/keyboard/ps2_keyboard.c @@ -3,14 +3,32 @@ #include "../../mm/mm.h" #include "../../mm/slab.h" #include "../../common/printk.h" +#include +#include +// 键盘输入缓冲区 static struct ps2_keyboard_input_buffer *kb_buf_ptr = NULL; +// 缓冲区等待队列 +static wait_queue_node_t ps2_keyboard_wait_queue; // 功能键标志变量 static bool shift_l, shift_r, ctrl_l, ctrl_r, alt_l, alt_r; static bool gui_l, gui_r, apps, insert, home, pgup, del, end, pgdn, arrow_u, arrow_l, arrow_d, arrow_r; static bool kp_forward_slash, kp_en; +/** + * @brief 重置ps2键盘输入缓冲区 + * + * @param kbp 缓冲区对象指针 + */ +static void ps2_keyboard_reset_buffer(struct ps2_keyboard_input_buffer *kbp) +{ + kbp->ptr_head = kb_buf_ptr->buffer; + kbp->ptr_tail = kb_buf_ptr->buffer; + kbp->count = 0; + // 清空输入缓冲区 + memset(kbp->buffer, 0, ps2_keyboard_buffer_size); +} struct apic_IO_APIC_RTE_entry entry; hardware_intr_controller ps2_keyboard_intr_controller = @@ -23,6 +41,120 @@ hardware_intr_controller ps2_keyboard_intr_controller = }; +/** + * @brief 打开键盘文件 + * + * @param inode 所在的inode + * @param filp 文件指针 + * @return long + */ +long ps2_keyboard_open(struct vfs_index_node_t *inode, struct vfs_file_t *filp) +{ + filp->private_data = (void *)kb_buf_ptr; + ps2_keyboard_reset_buffer(kb_buf_ptr); + return 0; +} + +/** + * @brief 关闭键盘文件 + * + * @param inode 所在的inode + * @param filp 文件指针 + * @return long + */ +long ps2_keyboard_close(struct vfs_index_node_t *inode, struct vfs_file_t *filp) +{ + filp->private_data = NULL; + ps2_keyboard_reset_buffer(kb_buf_ptr); + return 0; +} + +/** + * @brief 键盘io控制接口 + * + * @param inode 所在的inode + * @param filp 键盘文件指针 + * @param cmd 命令 + * @param arg 参数 + * @return long + */ +long ps2_keyboard_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *filp, uint64_t cmd, uint64_t arg) +{ + switch (cmd) + { + case KEYBOARD_CMD_RESET_BUFFER: + ps2_keyboard_reset_buffer(kb_buf_ptr); + break; + + default: + break; + } + return 0; +} + +/** + * @brief 读取键盘文件的操作接口 + * + * @param filp 文件指针 + * @param buf 输出缓冲区 + * @param count 要读取的字节数 + * @param position 读取的位置 + * @return long 读取的字节数 + */ +long ps2_keyboard_read(struct vfs_file_t *filp, char *buf, int64_t count, long *position) +{ + // 缓冲区为空则等待 + if (kb_buf_ptr->count == 0) + wait_queue_sleep_on(&ps2_keyboard_wait_queue); + + long counter = kb_buf_ptr->count >= count ? count : kb_buf_ptr->count; + + uint8_t *tail = kb_buf_ptr->ptr_tail; + + // 要读取的部分没有越过缓冲区末尾 + if (counter <= (kb_buf_ptr->buffer + ps2_keyboard_buffer_size - tail)) + { + copy_to_user(buf, tail, counter); + kb_buf_ptr->ptr_tail += counter; + } + else // 要读取的部分越过了缓冲区的末尾,进行循环 + { + uint64_t tmp = (kb_buf_ptr->buffer + ps2_keyboard_buffer_size - tail); + copy_to_user(buf, tail, tmp); + copy_to_user(buf, kb_buf_ptr->ptr_head, counter - tmp); + kb_buf_ptr->ptr_tail = kb_buf_ptr->ptr_head + (counter - tmp); + } + + kb_buf_ptr->count -= counter; + return counter; +} + +/** + * @brief 键盘文件写入接口(无作用,空) + * + * @param filp + * @param buf + * @param count + * @param position + * @return long + */ +long ps2_keyboard_write(struct vfs_file_t *filp, char *buf, int64_t count, long *position) +{ + return 0; +} +/** + * @brief ps2键盘驱动的虚拟文件接口 + * + */ +struct vfs_file_operations_t ps2_keyboard_fops = + { + .open = ps2_keyboard_open, + .close = ps2_keyboard_close, + .ioctl = ps2_keyboard_ioctl, + .read = ps2_keyboard_read, + .write = ps2_keyboard_write, +}; + /** * @brief 键盘中断处理函数(中断上半部) * 将数据存入缓冲区 @@ -49,6 +181,8 @@ void ps2_keyboard_handler(ul irq_num, ul param, struct pt_regs *regs) *kb_buf_ptr->ptr_head = x; ++(kb_buf_ptr->count); ++(kb_buf_ptr->ptr_head); + + wait_queue_wakeup(&ps2_keyboard_wait_queue, PROC_UNINTERRUPTIBLE); } /** * @brief 初始化键盘驱动程序的函数 @@ -56,7 +190,7 @@ void ps2_keyboard_handler(ul irq_num, ul param, struct pt_regs *regs) */ void ps2_keyboard_init() { - + // ======= 初始化键盘循环队列缓冲区 =========== // 申请键盘循环队列缓冲区的内存 @@ -102,6 +236,8 @@ void ps2_keyboard_init() alt_l = false; alt_r = false; + wait_queue_init(&ps2_keyboard_wait_queue, NULL); + // 注册中断处理程序 irq_register(PS2_KEYBOARD_INTR_VECTOR, &entry, &ps2_keyboard_handler, (ul)kb_buf_ptr, &ps2_keyboard_intr_controller, "ps/2 keyboard"); kdebug("kb registered."); diff --git a/kernel/driver/keyboard/ps2_keyboard.h b/kernel/driver/keyboard/ps2_keyboard.h index 2fa21d2c..307e3b8c 100644 --- a/kernel/driver/keyboard/ps2_keyboard.h +++ b/kernel/driver/keyboard/ps2_keyboard.h @@ -7,6 +7,8 @@ // 定义键盘循环队列缓冲区大小为100bytes #define ps2_keyboard_buffer_size 100 +#define KEYBOARD_CMD_RESET_BUFFER 1 + /** * @brief 键盘循环队列缓冲区结构体 * diff --git a/kernel/driver/video/video.c b/kernel/driver/video/video.c index 5232df64..c93a174e 100644 --- a/kernel/driver/video/video.c +++ b/kernel/driver/video/video.c @@ -87,7 +87,7 @@ int video_init(bool level) if (level) { // 启用双缓冲后,使能printk滚动动画 - printk_enable_animation(); + // 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); diff --git a/kernel/process/Makefile b/kernel/process/Makefile new file mode 100644 index 00000000..e2a13968 --- /dev/null +++ b/kernel/process/Makefile @@ -0,0 +1,16 @@ + +all: procs.o process.o wait_queue.o + +CFLAGS += -I . + + + +procs.o: proc.S + gcc -E proc.S > proc.s + as $(ASFLAGS) -o procs.o proc.s + +process.o: process.c + gcc $(CFLAGS) -c process.c -o process.o + +wait_queue.o: wait_queue.c + gcc $(CFLAGS) -c wait_queue.c -o wait_queue.o diff --git a/kernel/process/process.c b/kernel/process/process.c index 3d7e500c..8b8e849a 100644 --- a/kernel/process/process.c +++ b/kernel/process/process.c @@ -18,12 +18,7 @@ long process_global_pid = 1; // 系统中最大的pid extern void system_call(void); extern void kernel_thread_func(void); -/** - * @brief 将进程加入到调度器的就绪队列中 - * - * @param pcb 进程的pcb - */ -static inline void process_wakeup(struct process_control_block *pcb); + ul _stack_start; // initial proc的栈基地址(虚拟地址) struct mm_struct initial_mm = {0}; @@ -820,10 +815,12 @@ struct process_control_block *process_get_pcb(long pid) * * @param pcb 进程的pcb */ -static inline void process_wakeup(struct process_control_block *pcb) +void process_wakeup(struct process_control_block *pcb) { pcb->state = PROC_RUNNING; sched_cfs_enqueue(pcb); + // 将当前进程标志为需要调度,缩短新进程被wakeup的时间 + current_pcb->flags |= PF_NEED_SCHED; } /** diff --git a/kernel/process/process.h b/kernel/process/process.h index 2aabb251..9aa1e2c5 100644 --- a/kernel/process/process.h +++ b/kernel/process/process.h @@ -273,6 +273,13 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned */ struct process_control_block *process_get_pcb(long pid); +/** + * @brief 将进程加入到调度器的就绪队列中 + * + * @param pcb 进程的pcb + */ +void process_wakeup(struct process_control_block *pcb); + /** * @brief 切换页表 * @param prev 前一个进程的pcb diff --git a/kernel/process/semaphore.h b/kernel/process/semaphore.h index 47835049..8775abea 100644 --- a/kernel/process/semaphore.h +++ b/kernel/process/semaphore.h @@ -14,28 +14,8 @@ #include #include +#include "wait_queue.h" -/** - * @brief 信号量的等待队列 - * - */ -typedef struct -{ - struct List wait_list; - struct process_control_block *pcb; -} wait_queue_node_t; - -/** - * @brief 初始化信号量的等待队列 - * - * @param wait_queue 等待队列 - * @param pcb pcb - */ -void wait_queue_init(wait_queue_node_t *wait_queue, struct process_control_block *pcb) -{ - list_init(&wait_queue->wait_list); - wait_queue->pcb = pcb; -} /** * @brief 信号量的结构体 @@ -97,5 +77,7 @@ void semaphore_up(semaphore_t *sema) wq->pcb->state = PROC_RUNNING; sched_cfs_enqueue(wq->pcb); + // 当前进程缺少需要的资源,立即标为需要被调度 + current_pcb->flags |= PF_NEED_SCHED; } } \ No newline at end of file diff --git a/kernel/process/wait_queue.c b/kernel/process/wait_queue.c new file mode 100644 index 00000000..0890ad2d --- /dev/null +++ b/kernel/process/wait_queue.c @@ -0,0 +1,65 @@ +#include "wait_queue.h" +#include +#include + +/** + * @brief 初始化等待队列 + * + * @param wait_queue 等待队列 + * @param pcb pcb + */ +void wait_queue_init(wait_queue_node_t *wait_queue, struct process_control_block *pcb) +{ + list_init(&wait_queue->wait_list); + wait_queue->pcb = pcb; +} + +/** + * @brief 在等待队列上进行等待 + * + * @param wait_queue_head 队列头指针 + */ +void wait_queue_sleep_on(wait_queue_node_t *wait_queue_head) +{ + wait_queue_node_t wait; + wait_queue_init(&wait, current_pcb); + current_pcb->state = PROC_UNINTERRUPTIBLE; + list_append(&wait_queue_head->wait_list, &wait.wait_list); + + sched_cfs(); +} + +/** + * @brief 在等待队列上进行等待(允许中断) + * + * @param wait_queue_head 队列头指针 + */ +void wait_queue_sleep_on_interriptible(wait_queue_node_t * wait_queue_head) +{ + wait_queue_node_t wait; + wait_queue_init(&wait, current_pcb); + current_pcb->state = PROC_INTERRUPTIBLE; + list_append(&wait_queue_head->wait_list, &wait.wait_list); + + sched_cfs(); +} + +/** + * @brief 唤醒在等待队列的头部的进程 + * + * @param wait_queue_head + * @param state + */ +void wait_queue_wakeup(wait_queue_node_t * wait_queue_head, int64_t state) +{ + if(list_empty(&wait_queue_head->wait_list)) + return; + wait_queue_node_t * wait = container_of(list_next(&wait_queue_head->wait_list), wait_queue_node_t, wait_list); + + // 符合唤醒条件 + if(wait->pcb->state & state) + { + list_del(&wait->wait_list); + process_wakeup(wait->pcb); + } +} \ No newline at end of file diff --git a/kernel/process/wait_queue.h b/kernel/process/wait_queue.h new file mode 100644 index 00000000..3b3980be --- /dev/null +++ b/kernel/process/wait_queue.h @@ -0,0 +1,42 @@ +#pragma once +#include +#include +/** + * @brief 信号量的等待队列 + * + */ +typedef struct +{ + struct List wait_list; + struct process_control_block *pcb; +} wait_queue_node_t; + +/** + * @brief 初始化等待队列 + * + * @param wait_queue 等待队列 + * @param pcb pcb + */ +void wait_queue_init(wait_queue_node_t *wait_queue, struct process_control_block *pcb); + +/** + * @brief 在等待队列上进行等待 + * + * @param wait_queue_head 队列头指针 + */ +void wait_queue_sleep_on(wait_queue_node_t * wait_queue_head); + +/** + * @brief 在等待队列上进行等待(允许中断) + * + * @param wait_queue_head 队列头指针 + */ +void wait_queue_sleep_on_interriptible(wait_queue_node_t * wait_queue_head); + +/** + * @brief 唤醒在等待队列的头部的进程 + * + * @param wait_queue_head 队列头 + * @param state 要唤醒的进程的状态 + */ +void wait_queue_wakeup(wait_queue_node_t * wait_queue_head, int64_t state); \ No newline at end of file