浏览代码

new: 内核态fork

fslongjin 2 年之前
父节点
当前提交
2fd21e0395
共有 6 个文件被更改,包括 135 次插入27 次删除
  1. 5 2
      kernel/common/Makefile
  2. 21 0
      kernel/common/unistd.c
  3. 14 0
      kernel/common/unistd.h
  4. 92 22
      kernel/process/process.c
  5. 2 1
      kernel/process/process.h
  6. 1 2
      kernel/syscall/syscall.c

+ 5 - 2
kernel/common/Makefile

@@ -3,7 +3,7 @@ CFLAGS += -I .
 
 kernel_common_subdirs:=libELF math
 
-all: glib.o printk.o cpu.o bitree.o kfifo.o wait_queue.o mutex.o wait.o
+all: glib.o printk.o cpu.o bitree.o kfifo.o wait_queue.o mutex.o wait.o unistd.o
 	@list='$(kernel_common_subdirs)'; for subdir in $$list; do \
     		echo "make all in $$subdir";\
     		cd $$subdir;\
@@ -33,4 +33,7 @@ mutex.o: mutex.c
 	gcc $(CFLAGS) -c mutex.c -o mutex.o
 
 wait.o: sys/wait.c
-	gcc $(CFLAGS) -c sys/wait.c -o sys/wait.o
+	gcc $(CFLAGS) -c sys/wait.c -o sys/wait.o
+
+unistd.o: unistd.c
+	gcc $(CFLAGS) -c unistd.c -o unistd.o

+ 21 - 0
kernel/common/unistd.c

@@ -0,0 +1,21 @@
+#include <common/unistd.h>
+
+/**
+ * @brief fork当前进程
+ *
+ * @return pid_t
+ */
+pid_t fork(void)
+{
+    return (pid_t)enter_syscall_int(SYS_FORK, 0, 0, 0, 0, 0, 0, 0, 0);
+}
+
+/**
+ * @brief vfork当前进程
+ *
+ * @return pid_t
+ */
+pid_t vfork(void)
+{
+    return (pid_t)enter_syscall_int(SYS_VFORK, 0, 0, 0, 0, 0, 0, 0, 0);
+}

+ 14 - 0
kernel/common/unistd.h

@@ -12,3 +12,17 @@
 
 #include <syscall/syscall.h>
 #include <syscall/syscall_num.h>
+
+/**
+ * @brief fork当前进程
+ *
+ * @return pid_t
+ */
+pid_t fork(void);
+
+/**
+ * @brief vfork当前进程
+ *
+ * @return pid_t
+ */
+pid_t vfork(void);

+ 92 - 22
kernel/process/process.c

@@ -16,6 +16,8 @@
 #include <syscall/syscall.h>
 #include <syscall/syscall_num.h>
 #include <sched/sched.h>
+#include <common/unistd.h>
+#include <debug/traceback/traceback.h>
 
 #include <ktest/ktest.h>
 
@@ -121,7 +123,6 @@ void __switch_to(struct process_control_block *prev, struct process_control_bloc
 
     __asm__ __volatile__("movq	%0,	%%fs \n\t" ::"a"(next->thread->fs));
     __asm__ __volatile__("movq	%0,	%%gs \n\t" ::"a"(next->thread->gs));
-    // wrmsr(0x175, next->thread->rbp);
 }
 
 /**
@@ -375,7 +376,7 @@ ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[])
             strncpy((char *)(str_addr - argv_len), argv[argc], argv_len - 1);
             str_addr -= argv_len;
             dst_argv[argc] = (char *)str_addr;
-            //字符串加上结尾字符
+            // 字符串加上结尾字符
             ((char *)str_addr)[argv_len] = '\0';
         }
 
@@ -422,9 +423,20 @@ ul initial_kernel_thread(ul arg)
         ktest_start(ktest_test_kfifo, 0),
         ktest_start(ktest_test_mutex, 0),
     };
+    kinfo("Waiting test thread exit...");
     // 等待测试进程退出
-    for(int i=0;i<sizeof(tpid)/sizeof(uint64_t);++i)
+    for (int i = 0; i < sizeof(tpid) / sizeof(uint64_t); ++i)
         waitpid(tpid[i], NULL, NULL);
+    kinfo("All test done.");
+    // pid_t p = fork();
+    // if (p == 0)
+    // {
+    //     kdebug("in subproc, rflags=%#018lx", get_rflags());
+
+    //     while (1)
+    //         usleep(1000);
+    // }
+    // kdebug("subprocess pid=%d", p);
 
     // 准备切换到用户态
     struct pt_regs *regs;
@@ -439,8 +451,6 @@ ul initial_kernel_thread(ul arg)
     // 主动放弃内核线程身份
     current_pcb->flags &= (~PF_KTHREAD);
     kdebug("in initial_kernel_thread: flags=%ld", current_pcb->flags);
-    // current_pcb->mm->pgd = kmalloc(PAGE_4K_SIZE, 0);
-    // memset((void*)current_pcb->mm->pgd, 0, PAGE_4K_SIZE);
 
     regs = (struct pt_regs *)current_pcb->thread->rsp;
     // kdebug("current_pcb->thread->rsp=%#018lx", current_pcb->thread->rsp);
@@ -492,7 +502,7 @@ ul process_do_exit(ul code)
     sched_cfs();
 
     while (1)
-        hlt();
+        pause();
 }
 
 /**
@@ -604,11 +614,9 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
 {
     int retval = 0;
     struct process_control_block *tsk = NULL;
-    // kdebug("222\tregs.rip = %#018lx", regs->rip);
 
     // 为新的进程分配栈空间,并将pcb放置在底部
     tsk = (struct process_control_block *)kmalloc(STACK_SIZE, 0);
-    // kdebug("struct process_control_block ADDRESS=%#018lx", (uint64_t)tsk);
 
     if (tsk == NULL)
     {
@@ -620,12 +628,13 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
     // 将当前进程的pcb复制到新的pcb内
     memcpy(tsk, current_pcb, sizeof(struct process_control_block));
 
-    // kdebug("current_pcb->flags=%#010lx", current_pcb->flags);
-
-    // 将进程加入循环链表
+    // 初始化进程的循环链表结点
     list_init(&tsk->list);
 
-    // list_add(&initial_proc_union.pcb.list, &tsk->list);
+    // 判断是否为内核态调用fork
+    if (current_pcb->flags & PF_KTHREAD && stack_start != 0)
+        tsk->flags |= PF_KFORK;
+
     tsk->priority = 2;
     tsk->preempt_count = 0;
 
@@ -647,7 +656,6 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
     wait_queue_init(&tsk->wait_child_proc_exit, NULL);
 
     list_init(&tsk->list);
-    // list_add(&initial_proc_union.pcb.list, &tsk->list);
 
     retval = -ENOMEM;
 
@@ -670,6 +678,8 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
     // 拷贝成功
     retval = tsk->pid;
 
+    tsk->flags &= ~PF_KFORK;
+
     // 唤醒进程
     process_wakeup(tsk);
 
@@ -811,7 +821,6 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
     // 与父进程共享内存空间
     if (clone_flags & CLONE_VM)
     {
-        // kdebug("copy_vm\t current_pcb->mm->pgd=%#018lx", current_pcb->mm->pgd);
         pcb->mm = current_pcb->mm;
 
         return retval;
@@ -973,6 +982,48 @@ uint64_t process_exit_mm(struct process_control_block *pcb)
 
     return 0;
 }
+
+/**
+ * @brief 重写内核栈中的rbp地址
+ *
+ * @param new_regs 子进程的reg
+ * @param new_pcb 子进程的pcb
+ * @return int
+ */
+static int process_rewrite_rbp(struct pt_regs *new_regs, struct process_control_block *new_pcb)
+{
+
+    uint64_t new_top = ((uint64_t)new_pcb) + STACK_SIZE;
+    uint64_t old_top = (uint64_t)(current_pcb) + STACK_SIZE;
+
+    uint64_t *rbp = &new_regs->rbp;
+    uint64_t *tmp = rbp;
+
+    // 超出内核栈范围
+    if ((uint64_t)*rbp >= old_top || (uint64_t)*rbp < (old_top - STACK_SIZE))
+        return 0;
+
+    while (1)
+    {
+        // 计算delta
+        uint64_t delta = old_top - *rbp;
+        // 计算新的rbp值
+        uint64_t newVal = new_top - delta;
+
+        // 新的值不合法
+        if (unlikely((uint64_t)newVal >= new_top || (uint64_t)newVal < (new_top - STACK_SIZE)))
+            break;
+        // 将新的值写入对应位置
+        *rbp = newVal;
+        // 跳转栈帧
+        rbp = (uint64_t *)*rbp;
+    }
+
+    // 设置内核态fork返回到enter_syscall_int()函数内的时候,rsp寄存器的值
+    new_regs->rsp = new_top - (old_top - new_regs->rsp);
+    return 0;
+}
+
 /**
  * @brief 拷贝当前进程的线程结构体
  *
@@ -987,26 +1038,45 @@ uint64_t process_copy_thread(uint64_t clone_flags, struct process_control_block
     memset(thd, 0, sizeof(struct thread_struct));
     pcb->thread = thd;
 
+    struct pt_regs *child_regs = NULL;
     // 拷贝栈空间
-    struct pt_regs *child_regs = (struct pt_regs *)((uint64_t)pcb + STACK_SIZE - sizeof(struct pt_regs));
-    memcpy(child_regs, current_regs, sizeof(struct pt_regs));
+    if (pcb->flags & PF_KFORK) // 内核态下的fork
+    {
+        // 内核态下则拷贝整个内核栈
+        uint32_t size = ((uint64_t)current_pcb) + STACK_SIZE - (uint64_t)(current_regs);
+
+        child_regs = (struct pt_regs *)(((uint64_t)pcb) + STACK_SIZE - size);
+        memcpy(child_regs, (void *)current_regs, size);
+        // 然后重写新的栈中,每个栈帧的rbp值
+        process_rewrite_rbp(child_regs, pcb);
+    }
+    else
+    {
+        child_regs = (struct pt_regs *)((uint64_t)pcb + STACK_SIZE - sizeof(struct pt_regs));
+        memcpy(child_regs, current_regs, sizeof(struct pt_regs));
+        child_regs->rsp = stack_start;
+    }
 
     // 设置子进程的返回值为0
     child_regs->rax = 0;
-    child_regs->rsp = stack_start;
+    if (pcb->flags & PF_KFORK)
+        thd->rbp = (uint64_t)(child_regs + 1); // 设置新的内核线程开始执行时的rbp(也就是进入ret_from_system_call时的rbp)
+    else
+        thd->rbp = (uint64_t)pcb + STACK_SIZE;
 
-    thd->rbp = (uint64_t)pcb + STACK_SIZE;
+    // 设置新的内核线程开始执行的时候的rsp
     thd->rsp = (uint64_t)child_regs;
     thd->fs = current_pcb->thread->fs;
     thd->gs = current_pcb->thread->gs;
 
-    // kdebug("pcb->flags=%ld", pcb->flags);
-    // 根据是否为内核线程,设置进程的开始执行的地址
-    if (pcb->flags & PF_KTHREAD)
+    // 根据是否为内核线程、是否在内核态fork,设置进程的开始执行的地址
+    if (pcb->flags & PF_KFORK)
+        thd->rip = (uint64_t)ret_from_system_call;
+    else if (pcb->flags & PF_KTHREAD && (!(pcb->flags & PF_KFORK)))
         thd->rip = (uint64_t)kernel_thread_func;
     else
         thd->rip = (uint64_t)ret_from_system_call;
-    // kdebug("new proc's ret addr = %#018lx\tthd->rip=%#018lx   stack_start=%#018lx  child_regs->rsp = %#018lx, new_rip=%#018lx)", child_regs->rbx, thd->rip, stack_start, child_regs->rsp, child_regs->rip);
+
     return 0;
 }
 

+ 2 - 1
kernel/process/process.h

@@ -95,6 +95,7 @@ struct thread_struct
 #define PF_KTHREAD (1UL << 0)	 // 内核线程
 #define PF_NEED_SCHED (1UL << 1) // 进程需要被调度
 #define PF_VFORK (1UL << 2)		 // 标志进程是否由于vfork而存在资源共享
+#define PF_KFORK (1UL << 3)		 // 标志在内核态下调用fork(临时标记,do_fork()结束后会将其复位)
 
 /**
  * @brief 进程控制块
@@ -124,7 +125,7 @@ struct process_control_block
 	uint64_t addr_limit;
 
 	long pid;
-	long priority;		  // 优先级
+	long priority;			 // 优先级
 	int64_t virtual_runtime; // 虚拟运行时间
 
 	// 进程拥有的文件描述符的指针数组

+ 1 - 2
kernel/syscall/syscall.c

@@ -86,6 +86,7 @@ long enter_syscall_int(ul syscall_id, ul arg0, ul arg1, ul arg2, ul arg3, ul arg
         : "=a"(err_code)
         : "a"(syscall_id), "m"(arg0), "m"(arg1), "m"(arg2), "m"(arg3), "m"(arg4), "m"(arg5), "m"(arg6), "m"(arg7)
         : "memory", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "rcx", "rdx");
+
     return err_code;
 }
 
@@ -426,12 +427,10 @@ uint64_t sys_lseek(struct pt_regs *regs)
 
 uint64_t sys_fork(struct pt_regs *regs)
 {
-    // kdebug("sys_fork");
     return do_fork(regs, 0, regs->rsp, 0);
 }
 uint64_t sys_vfork(struct pt_regs *regs)
 {
-    kdebug("sys vfork");
     return do_fork(regs, CLONE_VM | CLONE_FS | CLONE_SIGNAL, regs->rsp, 0);
 }