Browse Source

bugfix:修复当使用sched()运行调度器,在切换进程的时候,由于不在中断上下文内,导致当前进程的上下文丢失的问题。 (#130)

bugfix:修复当使用sched()运行调度器,在切换进程的时候,由于不在中断上下文内,导致当前进程的上下文丢失的问题。
bugfix:修复切换进程的宏的汇编代码的损坏部分,未声明rax寄存器,从而导致的编译器未定义行为问题。
login 2 years ago
parent
commit
156949680c

+ 1 - 1
kernel/src/process/process.c

@@ -513,7 +513,7 @@ ul initial_kernel_thread(ul arg)
     // kdebug("current_pcb->thread->rsp=%#018lx", current_pcb->thread->rsp);
     current_pcb->flags = 0;
     // 将返回用户层的代码压入堆栈,向rdx传入regs的地址,然后jmp到do_execve这个系统调用api的处理函数
-    // 这里的设计思路和switch_proc类似 加载用户态程序:shell.elf
+    // 这里的设计思路和switch_to类似 加载用户态程序:shell.elf
     __asm__ __volatile__("movq %1, %%rsp   \n\t"
                          "pushq %2    \n\t"
                          "jmp do_execve  \n\t" ::"D"(current_pcb->thread->rsp),

+ 4 - 4
kernel/src/process/process.h

@@ -51,23 +51,23 @@ extern uint64_t process_exit_files(struct process_control_block *pcb);
  * 然后调用__switch_to切换栈,配置其他信息,最后恢复下一个进程的rax rbp。
  */
 
-#define switch_proc(prev, next)                                                                                        \
+#define switch_to(prev, next)                                                                                          \
     do                                                                                                                 \
     {                                                                                                                  \
         __asm__ __volatile__("pushq	%%rbp	\n\t"                                                                        \
                              "pushq	%%rax	\n\t"                                                                        \
                              "movq	%%rsp,	%0	\n\t"                                                                     \
                              "movq	%2,	%%rsp	\n\t"                                                                     \
-                             "leaq	switch_proc_ret_addr(%%rip),	%%rax	\n\t"                                            \
+                             "leaq	2f(%%rip),	%%rax	\n\t"                                                              \
                              "movq	%%rax,	%1	\n\t"                                                                     \
                              "pushq	%3		\n\t"                                                                          \
                              "jmp	__switch_to	\n\t"                                                                    \
-                             "switch_proc_ret_addr:	\n\t"                                                              \
+                             "2:	\n\t"                                                                                 \
                              "popq	%%rax	\n\t"                                                                         \
                              "popq	%%rbp	\n\t"                                                                         \
                              : "=m"(prev->thread->rsp), "=m"(prev->thread->rip)                                        \
                              : "m"(next->thread->rsp), "m"(next->thread->rip), "D"(prev), "S"(next)                    \
-                             : "memory");                                                                              \
+                             : "memory", "rax");                                                                       \
     } while (0)
 
 /**

+ 23 - 13
kernel/src/sched/cfs.c

@@ -1,7 +1,7 @@
 #include "cfs.h"
 #include <common/kprint.h>
-#include <driver/video/video.h>
 #include <common/spinlock.h>
+#include <driver/video/video.h>
 
 struct sched_queue_t sched_cfs_ready_queue[MAX_CPU_NUM]; // 就绪队列
 
@@ -18,7 +18,8 @@ struct process_control_block *sched_cfs_dequeue()
         return &initial_proc_union.pcb;
     }
 
-    struct process_control_block *proc = container_of(list_next(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list), struct process_control_block, list);
+    struct process_control_block *proc = container_of(
+        list_next(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list), struct process_control_block, list);
 
     list_del(&proc->list);
     --sched_cfs_ready_queue[proc_current_cpu_id].count;
@@ -34,7 +35,8 @@ void sched_cfs_enqueue(struct process_control_block *pcb)
 {
     if (pcb == initial_proc[proc_current_cpu_id])
         return;
-    struct process_control_block *proc = container_of(list_next(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list), struct process_control_block, list);
+    struct process_control_block *proc = container_of(
+        list_next(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list), struct process_control_block, list);
     if ((list_empty(&sched_cfs_ready_queue[proc_current_cpu_id].proc_queue.list)) == 0)
     {
         while (proc->virtual_runtime < pcb->virtual_runtime)
@@ -58,12 +60,16 @@ void sched_cfs()
     current_pcb->flags &= ~PF_NEED_SCHED;
     // kdebug("current_pcb pid= %d", current_pcb->pid);
     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)) // 当前进程运行时间大于了下一进程的运行时间,进行切换
+    // 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)) // 当前进程运行时间大于了下一进程的运行时间,进行切换
     {
 
-        // kdebug("current_pcb->virtual_runtime = %d,proc->vt= %d", current_pcb->virtual_runtime, proc->virtual_runtime);
-        if (current_pcb->state & PROC_RUNNING) // 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理
+        // kdebug("current_pcb->virtual_runtime = %d,proc->vt= %d", current_pcb->virtual_runtime,
+        // proc->virtual_runtime);
+        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)
@@ -72,18 +78,20 @@ void sched_cfs()
             {
             case 0:
             case 1:
-                sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = 4 / sched_cfs_ready_queue[proc_current_cpu_id].count;
+                sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies =
+                    4 / sched_cfs_ready_queue[proc_current_cpu_id].count;
                 break;
             case 2:
             default:
-                sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = (4 / sched_cfs_ready_queue[proc_current_cpu_id].count) << 2;
+                sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies =
+                    (4 / sched_cfs_ready_queue[proc_current_cpu_id].count) << 2;
                 break;
             }
         }
 
-        process_switch_mm(proc);
-
+        barrier();
         switch_proc(current_pcb, proc);
+        barrier();
     }
     else // 不进行切换
     {
@@ -96,12 +104,14 @@ void sched_cfs()
             {
             case 0:
             case 1:
-                sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = 4 / sched_cfs_ready_queue[proc_current_cpu_id].count;
+                sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies =
+                    4 / sched_cfs_ready_queue[proc_current_cpu_id].count;
                 break;
             case 2:
             default:
 
-                sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies = (4 / sched_cfs_ready_queue[proc_current_cpu_id].count) << 2;
+                sched_cfs_ready_queue[proc_current_cpu_id].cpu_exec_proc_jiffies =
+                    (4 / sched_cfs_ready_queue[proc_current_cpu_id].count) << 2;
                 break;
             }
         }

+ 21 - 3
kernel/src/sched/sched.c

@@ -1,9 +1,9 @@
 #include "sched.h"
 #include <common/kprint.h>
 #include <common/spinlock.h>
+#include <common/string.h>
 #include <driver/video/video.h>
 #include <sched/cfs.h>
-#include <common/string.h>
 
 /**
  * @brief
@@ -60,10 +60,10 @@ void sched_enqueue(struct process_control_block *pcb)
 }
 
 /**
- * @brief 包裹sched_cfs(),调度函数
+ * @brief 该函数只能由sys_sched调用
  *
  */
-void sched()
+static void __sched()
 {
     sched_cfs();
 }
@@ -73,5 +73,23 @@ void sched_init()
     sched_cfs_init();
 }
 
+uint64_t sys_sched(struct pt_regs *regs)
+{
+    if(user_mode(regs)){
+        return -EPERM;
+    }
+    __sched();
+}
 
+void sched()
+{
+    
+    enter_syscall_int(SYS_SCHED, 0, 0, 0, 0, 0, 0, 0, 0);
+}
 
+void switch_proc(struct process_control_block *prev, struct process_control_block *proc)
+{
+    process_switch_mm(proc);
+    io_mfence();
+    switch_to(prev, proc);
+}

+ 1 - 0
kernel/src/sched/sched.h

@@ -77,3 +77,4 @@ void sched_init();
  */
 void sched_update_jiffies();
 
+void switch_proc(struct process_control_block *prev, struct process_control_block *proc);

+ 3 - 1
kernel/src/syscall/syscall.c

@@ -23,6 +23,7 @@ extern uint64_t sys_kill(struct pt_regs *regs);
 extern uint64_t sys_sigaction(struct pt_regs * regs);
 extern uint64_t sys_rt_sigreturn(struct pt_regs * regs);
 extern uint64_t sys_getpid(struct pt_regs * regs);
+extern uint64_t sys_sched(struct pt_regs * regs);
 
 /**
  * @brief 导出系统调用处理函数的符号
@@ -592,6 +593,7 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = {
     [24] = sys_sigaction,
     [25] = sys_rt_sigreturn,
     [26] = sys_getpid,
-    [27 ... 254] = system_call_not_exists,
+    [27] = sys_sched,
+    [28 ... 254] = system_call_not_exists,
     [255] = sys_ahci_end_req,
 };

+ 2 - 1
kernel/src/syscall/syscall_num.h

@@ -37,6 +37,7 @@
 #define SYS_KILL 23         // kill一个进程(向这个进程发出信号)
 #define SYS_SIGACTION 24    // 设置进程的信号处理动作
 #define SYS_RT_SIGRETURN 25 // 从信号处理函数返回
-#define SYS_GETPID 26 // 获取当前进程的pid(进程标识符)
+#define SYS_GETPID 26       // 获取当前进程的pid(进程标识符)
+#define SYS_SCHED 27        // 让系统立即运行调度器(该系统调用不能由运行在Ring3的程序发起)
 
 #define SYS_AHCI_END_REQ 255 // AHCI DMA请求结束end_request的系统调用