new: 内核态fork

This commit is contained in:
fslongjin 2022-08-01 11:34:06 +08:00
parent 311a6181b5
commit 2fd21e0395
6 changed files with 135 additions and 27 deletions

View File

@ -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;\
@ -34,3 +34,6 @@ mutex.o: mutex.c
wait.o: sys/wait.c
gcc $(CFLAGS) -c sys/wait.c -o sys/wait.o
unistd.o: unistd.c
gcc $(CFLAGS) -c unistd.c -o unistd.o

21
kernel/common/unistd.c Normal file
View File

@ -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);
}

View File

@ -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);

View File

@ -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));
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;
// 设置新的内核线程开始执行的时候的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;
}

View File

@ -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

View File

@ -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);
}