🆕 exec (存在bug

This commit is contained in:
fslongjin
2022-05-31 21:55:06 +08:00
parent 844e66f6bb
commit e2a59dbd43
24 changed files with 494 additions and 90 deletions

View File

@ -198,7 +198,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long error_code)
__asm__ __volatile__("movq %%cr2, %0":"=r"(cr2)::"memory");
kerror("do_page_fault(14),Error code :%#018lx,RSP:%#018lx,RIP:%#018lx CPU:%d\n",error_code , regs->rsp , regs->rip, proc_current_cpu_id);
kerror("do_page_fault(14),Error code :%#018lx,RSP:%#018lx,RIP:%#018lx CPU:%d, pid=%d\n",error_code , regs->rsp , regs->rip, proc_current_cpu_id, current_pcb->pid);
if(!(error_code & 0x01))
printk_color(RED,BLACK,"Page Not-Present,\t");

View File

@ -31,4 +31,4 @@ ENTRY(kernel_thread_func)
movq %rdx, %rdi
callq *%rbx
movq %rax, %rdi
callq process_thread_do_exit
callq process_do_exit

View File

@ -107,6 +107,14 @@ void __switch_to(struct process_control_block *prev, struct process_control_bloc
// set_tss64((uint *)phys_2_virt(TSS64_Table), initial_tss[0].rsp0, initial_tss[0].rsp1, initial_tss[0].rsp2, initial_tss[0].ist1,
// initial_tss[0].ist2, initial_tss[0].ist3, initial_tss[0].ist4, initial_tss[0].ist5, initial_tss[0].ist6, initial_tss[0].ist7);
if (next->pid == 2)
{
struct pt_regs *child_regs = (struct pt_regs *)next->thread->rsp;
kdebug("next->thd->rip=%#018lx", next->thread->rip);
kdebug("next proc's ret addr = %#018lx\t next child_regs->rsp = %#018lx, next new_rip=%#018lx)", child_regs->rip, child_regs->rsp, child_regs->rip);
}
__asm__ __volatile__("movq %%fs, %0 \n\t"
: "=a"(prev->thread->fs));
__asm__ __volatile__("movq %%gs, %0 \n\t"
@ -416,7 +424,8 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
if ((unsigned long)filp <= 0)
{
kdebug("(unsigned long)filp=%d", (long)filp);
return (unsigned long)filp;
retval = -ENOEXEC;
goto load_elf_failed;
}
Elf64_Phdr *phdr = buf;
@ -441,7 +450,7 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
if (!mm_check_mapped((uint64_t)current_pcb->mm->pgd, virt_base)) // 未映射,则新增物理页
{
mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, virt_base, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true);
memset((void*)virt_base, 0, PAGE_2M_SIZE);
memset((void *)virt_base, 0, PAGE_2M_SIZE);
}
pos = filp->file_ops->lseek(filp, pos, SEEK_SET);
int64_t val = 0;
@ -465,7 +474,7 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
regs->rbp = current_pcb->mm->stack_start;
mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, current_pcb->mm->stack_start - PAGE_2M_SIZE, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true);
// 清空栈空间
memset((void*)(current_pcb->mm->stack_start - PAGE_2M_SIZE), 0, PAGE_2M_SIZE);
memset((void *)(current_pcb->mm->stack_start - PAGE_2M_SIZE), 0, PAGE_2M_SIZE);
load_elf_failed:;
if (buf != NULL)
@ -477,19 +486,12 @@ load_elf_failed:;
*
* @param regs 当前进程的寄存器
* @param path 可执行程序的路径
* @param argv 参数列表
* @param envp 环境变量
* @return ul 错误码
*/
ul do_execve(struct pt_regs *regs, char *path)
ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[])
{
// 选择这两个寄存器是对应了sysexit指令的需要
regs->rip = 0x800000; // rip 应用层程序的入口地址 这里的地址选择没有特殊要求,只要是未使用的内存区域即可。
regs->rsp = 0xa00000; // rsp 应用层程序的栈顶地址
regs->cs = USER_CS | 3;
regs->ds = USER_DS | 3;
regs->ss = USER_DS | 0x3;
regs->rflags = 0x200246;
regs->rax = 1;
regs->es = 0;
kdebug("do_execve is running...");
@ -512,14 +514,10 @@ ul do_execve(struct pt_regs *regs, char *path)
// 拷贝内核空间的页表指针
memcpy(phys_2_virt(new_mms->pgd) + 256, phys_2_virt(initial_proc[proc_current_cpu_id]) + 256, PAGE_4K_SIZE / 2);
}
/**
* @todo: 加载elf文件并映射对应的页
*
*/
// 映射1个2MB的物理页
// 设置用户栈和用户堆的基地址
unsigned long stack_start_addr = 0x6fffffc00000;
uint64_t brk_start_addr = 0x6fffffc00000;
const uint64_t brk_start_addr = 0x6fffffc00000;
process_switch_mm(current_pcb);
@ -544,9 +542,49 @@ ul do_execve(struct pt_regs *regs, char *path)
// 清除进程的vfork标志位
current_pcb->flags &= ~PF_VFORK;
process_load_elf_file(regs, path);
// 加载elf格式的可执行文件
int tmp = process_load_elf_file(regs, path);
if (tmp < 0)
return tmp;
// 拷贝参数列表
if (argv != NULL)
{
int argc = 0;
// 目标程序的argv基地址指针最大8个参数
char **dst_argv = (char **)(stack_start_addr - (sizeof(char **) << 3));
uint64_t str_addr = (uint64_t)dst_argv;
for (argc = 0; argc < 8 && argv[argc] != NULL; ++argc)
{
// 测量参数的长度最大1023
int argv_len = strnlen_user(argv[argc], 1023) + 1;
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';
}
// 重新设定栈基址,并预留空间防止越界
stack_start_addr = str_addr - 8;
current_pcb->mm->stack_start = stack_start_addr;
regs->rsp = regs->rbp = stack_start_addr;
// 传递参数
regs->rdi = argc;
regs->rsi = (uint64_t)dst_argv;
}
kdebug("execve ok");
regs->cs = USER_CS | 3;
regs->ds = USER_DS | 3;
regs->ss = USER_DS | 0x3;
regs->rflags = 0x200246;
regs->rax = 1;
regs->es = 0;
return 0;
}
@ -570,7 +608,7 @@ 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);
@ -584,23 +622,47 @@ ul initial_kernel_thread(ul arg)
__asm__ __volatile__("movq %1, %%rsp \n\t"
"pushq %2 \n\t"
"jmp do_execve \n\t" ::"D"(current_pcb->thread->rsp),
"m"(current_pcb->thread->rsp), "m"(current_pcb->thread->rip), "S"("/shell.elf")
"m"(current_pcb->thread->rsp), "m"(current_pcb->thread->rip), "S"("/shell.elf"), "c"(NULL), "d"(NULL)
: "memory");
return 1;
}
/**
* @brief 当子进程退出后向父进程发送通知
*
*/
void process_exit_notify()
{
wait_queue_wakeup(&current_pcb->parent_pcb->wait_child_proc_exit, PROC_INTERRUPTIBLE);
}
/**
* @brief 进程退出时执行的函数
*
* @param code 返回码
* @return ul
*/
ul process_thread_do_exit(ul code)
ul process_do_exit(ul code)
{
kinfo("thread_exiting..., code is %#018lx.", code);
kinfo("process exiting..., code is %#018lx.", code);
cli();
struct process_control_block *pcb = current_pcb;
// 进程退出时释放资源
process_exit_files(pcb);
process_exit_thread(pcb);
// todo: 可否在这里释放内存结构体?(在判断共享页引用问题之后)
pcb->state = PROC_ZOMBIE;
pcb->exit_code = pcb;
sti();
process_exit_notify();
sched_cfs();
while (1)
;
hlt();
}
/**
@ -750,6 +812,10 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
tsk->cpu_id = proc_current_cpu_id;
tsk->state = PROC_UNINTERRUPTIBLE;
tsk->parent_pcb = current_pcb;
wait_queue_init(&tsk->wait_child_proc_exit, NULL);
list_init(&tsk->list);
// list_add(&initial_proc_union.pcb.list, &tsk->list);
@ -773,6 +839,8 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
// 拷贝成功
retval = tsk->pid;
kdebug("fork done: tsk->pid=%d", tsk->pid);
// 唤醒进程
process_wakeup(tsk);
@ -945,13 +1013,15 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
pdpt_t *current_pdpt = (pdpt_t *)phys_2_virt(*(uint64_t *)(current_pgd + i) & (~0xfffUL));
// kdebug("current pdpt=%#018lx \t (current_pgd + i)->pml4t=%#018lx", current_pdpt, *(uint64_t *)(current_pgd+i));
kdebug("i=%d, current pdpt=%#018lx \t (current_pgd + i)->pml4t=%#018lx", i, current_pdpt, *(uint64_t *)(current_pgd + i));
// 设置二级页表
for (int j = 0; j < 512; ++j)
{
if (*(uint64_t *)(current_pdpt + j) == 0)
continue;
kdebug("j=%d *(uint64_t *)(current_pdpt + j)=%#018lx", j, *(uint64_t *)(current_pdpt + j));
// 分配新的三级页表
pdt_t *new_pdt = (pdt_t *)kmalloc(PAGE_4K_SIZE, 0);
memset(new_pdt, 0, PAGE_4K_SIZE);
@ -966,13 +1036,15 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
{
if ((current_pdt + k)->pdt == 0)
continue;
kdebug("k=%d, (current_pdt + k)->pdt=%#018lx", k, (current_pdt + k)->pdt);
// 获取一个新页
struct Page *pg = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED);
set_pdt((uint64_t *)(new_pdt + k), mk_pdt(pg->addr_phys, (current_pdt + k)->pdt & 0x1fffUL));
set_pdt((uint64_t *)(new_pdt + k), mk_pdt(pg->addr_phys, (current_pdt + k)->pdt & 0x1ffUL));
kdebug("k=%d, cpy dest=%#018lx, src=%#018lx", k, phys_2_virt(pg->addr_phys), phys_2_virt((current_pdt + k)->pdt & (~0x1ffUL)));
// 拷贝数据
memcpy(phys_2_virt(pg->addr_phys), phys_2_virt((current_pdt + k)->pdt & (~0x1fffUL)), PAGE_2M_SIZE);
memcpy(phys_2_virt(pg->addr_phys), phys_2_virt((current_pdt + k)->pdt & (~0x1ffUL)), PAGE_2M_SIZE);
}
}
}
@ -1070,12 +1142,13 @@ uint64_t process_copy_thread(uint64_t clone_flags, struct process_control_block
thd->fs = current_pcb->thread->fs;
thd->gs = current_pcb->thread->gs;
kdebug("pcb->flags=%ld", pcb->flags);
// 根据是否为内核线程,设置进程的开始执行的地址
if (pcb->flags & PF_KTHREAD)
thd->rip = (uint64_t)kernel_thread_func;
else
thd->rip = (uint64_t)ret_from_system_call;
kdebug("new proc's ret addr = %#018lx\tchild_regs->rsp = %#018lx", child_regs->rbx, child_regs->rsp);
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

@ -17,6 +17,7 @@
#include "ptrace.h"
#include <common/errno.h>
#include <filesystem/VFS/VFS.h>
#include <process/wait_queue.h>
// 进程最大可拥有的文件描述符数量
#define PROC_MAX_FD_NUM 16
@ -134,6 +135,9 @@ struct process_control_block
struct process_control_block *next_pcb;
// 父进程的pcb
struct process_control_block *parent_pcb;
int32_t exit_code; // 进程退出时的返回码
wait_queue_node_t wait_child_proc_exit; // 子进程退出等待队列
};
// 将进程的pcb和内核栈融合到一起,8字节对齐
@ -159,7 +163,9 @@ union proc_union
.cpu_id = 0, \
.fds = {0}, \
.next_pcb = &proc, \
.parent_pcb = &proc \
.parent_pcb = &proc, \
.exit_code = 0, \
.wait_child_proc_exit = 0 \
}
/**
@ -280,6 +286,39 @@ struct process_control_block *process_get_pcb(long pid);
*/
void process_wakeup(struct process_control_block *pcb);
/**
* @brief 使当前进程去执行新的代码
*
* @param regs 当前进程的寄存器
* @param path 可执行程序的路径
* @param argv 参数列表
* @param envp 环境变量
* @return ul 错误码
*/
ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[]);
/**
* @brief 释放进程的页表
*
* @param pcb 要被释放页表的进程
* @return uint64_t
*/
uint64_t process_exit_mm(struct process_control_block *pcb);
/**
* @brief 进程退出时执行的函数
*
* @param code 返回码
* @return ul
*/
ul process_do_exit(ul code);
/**
* @brief 当子进程退出后向父进程发送通知
*
*/
void process_exit_notify();
/**
* @brief 切换页表
* @param prev 前一个进程的pcb
@ -305,4 +344,4 @@ extern struct tss_struct initial_tss[MAX_CPU_NUM];
extern struct mm_struct initial_mm;
extern struct thread_struct initial_thread;
extern union proc_union initial_proc_union;
extern struct process_control_block *initial_proc[MAX_CPU_NUM];
extern struct process_control_block *initial_proc[MAX_CPU_NUM];

View File

@ -1,6 +1,6 @@
#pragma once
#include <common/glib.h>
#include <process/process.h>
// #include <process/process.h>
/**
* @brief 信号量的等待队列
*

View File

@ -9,6 +9,7 @@
#include <filesystem/fat32/fat32.h>
#include <filesystem/VFS/VFS.h>
#include <driver/keyboard/ps2_keyboard.h>
#include <process/process.h>
// 导出系统调用入口函数定义在entry.S中
extern void system_call(void);
@ -440,8 +441,9 @@ uint64_t sys_sbrk(struct pt_regs *regs)
if ((__int128_t)current_pcb->mm->brk_end + (__int128_t)regs->r8 < current_pcb->mm->brk_start)
return retval;
}
// kdebug("do brk");
uint64_t new_brk = mm_do_brk(current_pcb->mm->brk_end, (int64_t)regs->r8); // 调整堆内存空间
// kdebug("do brk done, new_brk = %#018lx", new_brk);
current_pcb->mm->brk_end = new_brk;
return retval;
}
@ -549,6 +551,110 @@ uint64_t sys_getdents(struct pt_regs *regs)
return retval;
}
/**
* @brief 执行新的程序
*
* @param user_path(r8寄存器) 文件路径
* @param argv(r9寄存器) 参数列表
* @return uint64_t
*/
uint64_t sys_execve(struct pt_regs *regs)
{
kdebug("sys_execve");
char *user_path = (char *)regs->r8;
char **argv = (char **)regs->r9;
int path_len = strnlen_user(user_path, PAGE_4K_SIZE);
kdebug("path_len=%d", path_len);
if (path_len >= PAGE_4K_SIZE)
return -ENAMETOOLONG;
else if (path_len <= 0)
return -EFAULT;
char *path = (char *)kmalloc(path_len + 1, 0);
if (path == NULL)
return -ENOMEM;
memset(path, 0, path_len + 1);
kdebug("before copy file path from user");
// 拷贝文件路径
strncpy_from_user(path, user_path, path_len);
path[path_len] = '\0';
kdebug("before do_execve, path = %s", path);
// 执行新的程序
uint64_t retval = do_execve(regs, path, argv, NULL);
kfree(path);
return retval;
}
/**
* @brief 等待进程退出
*
* @param pid 目标进程id
* @param status 返回的状态信息
* @param options 等待选项
* @param rusage
* @return uint64_t
*/
uint64_t sys_wait4(struct pt_regs *regs)
{
uint64_t pid = regs->r8;
int *status = (int *)regs->r9;
int options = regs->r10;
void *rusage = regs->r11;
struct process_control_block *proc = NULL;
struct process_control_block *child_proc = NULL;
// 查找pid为指定值的进程
// ps: 这里判断子进程的方法没有按照posix 2008来写。
// todo: 根据进程树判断是否为当前进程的子进程
for (proc = &initial_proc_union.pcb; proc->next_pcb != &initial_proc_union.pcb; proc = proc->next_pcb)
{
if (proc->next_pcb->pid == pid)
{
child_proc = proc->next_pcb;
break;
}
}
if (child_proc == NULL)
return -ECHILD;
// 暂时不支持options选项该值目前必须为0
if (options != 0)
return -EINVAL;
// 如果子进程没有退出,则等待其退出
while (child_proc->state != PROC_ZOMBIE)
wait_queue_sleep_on_interriptible(&current_pcb->wait_child_proc_exit);
// 拷贝子进程的返回码
copy_to_user(status, child_proc->exit_code, sizeof(int));
proc->next_pcb = child_proc->next_pcb;
// 释放子进程的页表
process_exit_mm(child_proc);
// 释放子进程的pcb
kfree(child_proc);
return 0;
}
/**
* @brief 进程退出
*
* @param exit_code 退出返回码
* @return uint64_t
*/
uint64_t sys_exit(struct pt_regs * regs)
{
return process_do_exit(regs->r8);
}
ul sys_ahci_end_req(struct pt_regs *regs)
{
ahci_end_request();
@ -579,5 +685,8 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] =
[11] = sys_reboot,
[12] = sys_chdir,
[13] = sys_getdents,
[14 ... 254] = system_call_not_exists,
[14] = sys_execve,
[15] = sys_wait4,
[16] = sys_exit,
[17 ... 254] = system_call_not_exists,
[255] = sys_ahci_end_req};

View File

@ -20,8 +20,12 @@
#define SYS_VFORK 8
#define SYS_BRK 9
#define SYS_SBRK 10
#define SYS_REBOOT 11 // 重启
#define SYS_CHDIR 12 // 切换工作目录
#define SYS_GET_DENTS 13 // 获取目录中的数据
#define SYS_EXECVE 14 // 执行新的应用程序
#define SYS_WAIT4 15 // 等待进程退出
#define SYS_EXIT 16 // 进程退出
#define SYS_AHCI_END_REQ 255 // AHCI DMA请求结束end_request的系统调用