diff --git a/kernel/common/Makefile b/kernel/common/Makefile index 81506e41..df1b3760 100644 --- a/kernel/common/Makefile +++ b/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 \ No newline at end of file + gcc $(CFLAGS) -c sys/wait.c -o sys/wait.o + +unistd.o: unistd.c + gcc $(CFLAGS) -c unistd.c -o unistd.o \ No newline at end of file diff --git a/kernel/common/unistd.c b/kernel/common/unistd.c new file mode 100644 index 00000000..b534b283 --- /dev/null +++ b/kernel/common/unistd.c @@ -0,0 +1,21 @@ +#include + +/** + * @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); +} \ No newline at end of file diff --git a/kernel/common/unistd.h b/kernel/common/unistd.h index cc10c743..5b62fb3b 100644 --- a/kernel/common/unistd.h +++ b/kernel/common/unistd.h @@ -12,3 +12,17 @@ #include #include + +/** + * @brief fork当前进程 + * + * @return pid_t + */ +pid_t fork(void); + +/** + * @brief vfork当前进程 + * + * @return pid_t + */ +pid_t vfork(void); \ No newline at end of file diff --git a/kernel/process/process.c b/kernel/process/process.c index 9cd33b6c..077c46d6 100644 --- a/kernel/process/process.c +++ b/kernel/process/process.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include @@ -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;iflags &= (~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; } diff --git a/kernel/process/process.h b/kernel/process/process.h index d383243e..d1c7b28a 100644 --- a/kernel/process/process.h +++ b/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; // 虚拟运行时间 // 进程拥有的文件描述符的指针数组 diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index b8b920a3..af5bbe63 100644 --- a/kernel/syscall/syscall.c +++ b/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); }