完善execve,使其能加载用户程序文件

This commit is contained in:
fslongjin 2022-05-05 14:14:34 +08:00
parent 1801ddffbd
commit 099b24539a
6 changed files with 161 additions and 42 deletions

View File

@ -362,7 +362,7 @@ static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_
port->ci = 1; // Issue command
current_pcb->flags |= PF_NEED_SCHED;
//sched_cfs();
sched_cfs();
int retval = AHCI_SUCCESS;
while (1)
@ -383,7 +383,7 @@ static bool ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_
kerror("Write disk error");
retval = E_TASK_FILE_ERROR;
}
kdebug("ahci write retval=%d", retval);
// kdebug("ahci write retval=%d", retval);
enter_syscall_int(SYS_AHCI_END_REQ, 0, 0, 0, 0, 0, 0, 0, 0);
return retval;
}

View File

@ -622,9 +622,9 @@ void mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul
* @param length
* @param user 访
*/
void mm_map_proc_page_table(ul *proc_page_table_addr, bool is_phys, ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool user)
void mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool user)
{
// kdebug("proc_page_table_addr=%#018lx",proc_page_table_addr);
// 计算线性地址对应的pml4页表项的地址
ul *tmp;
if (is_phys)
@ -632,14 +632,14 @@ void mm_map_proc_page_table(ul *proc_page_table_addr, bool is_phys, ul virt_addr
else
tmp = (ul *)((ul)proc_page_table_addr & (~0xfffUL)) + ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff);
kdebug("tmp = %#018lx", tmp);
// kdebug("tmp = %#018lx", tmp);
if (*tmp == 0)
{
ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
memset(virt_addr, 0, PAGE_4K_SIZE);
set_pml4t(tmp, mk_pml4t(virt_2_phys(virt_addr), (user ? PAGE_USER_PGT : PAGE_KERNEL_PGT)));
}
kdebug("*tmp = %#018lx", *tmp);
// kdebug("*tmp = %#018lx", *tmp);
if (is_phys)
tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr_start >> PAGE_1G_SHIFT) & 0x1ff));

View File

@ -373,7 +373,7 @@ void mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flag
* @param length
* @param user 访
*/
void mm_map_proc_page_table(ul *proc_page_table_addr, bool is_phys, ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool user);
void mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool user);
void mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul flags);

View File

@ -44,6 +44,59 @@ struct process_control_block *initial_proc[MAX_CPU_NUM] = {&initial_proc_union.p
// 为每个核心初始化初始进程的tss
struct tss_struct initial_tss[MAX_CPU_NUM] = {[0 ... MAX_CPU_NUM - 1] = INITIAL_TSS};
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb);
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_files(uint64_t clone_flags, struct process_control_block *pcb);
/**
* @brief
*
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_exit_files(struct process_control_block *pcb);
/**
* @brief
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb);
/**
* @brief
*
* @param pcb
* @return uint64_t
*/
uint64_t process_exit_mm(struct process_control_block *pcb);
/**
* @brief 线
*
* @param clone_flags
* @param pcb pcb
* @return uint64_t
*/
uint64_t process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start, uint64_t stack_size, struct pt_regs *current_regs);
void process_exit_thread(struct process_control_block *pcb);
/**
* @brief
*
@ -273,9 +326,10 @@ void user_level_function()
* @brief 使
*
* @param regs
* @param path
* @return ul
*/
ul do_execve(struct pt_regs *regs)
ul do_execve(struct pt_regs *regs, char *path)
{
// 选择这两个寄存器是对应了sysexit指令的需要
regs->rip = 0x800000; // rip 应用层程序的入口地址 这里的地址选择没有特殊要求,只要是未使用的内存区域即可。
@ -287,35 +341,75 @@ ul do_execve(struct pt_regs *regs)
regs->rax = 1;
regs->es = 0;
// kdebug("do_execve is running...");
kdebug("do_execve is running...");
// 映射起始页面
// mm_map_proc_page_table(get_CR3(), true, 0x800000, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true);
// 当前进程正在与父进程共享地址空间,需要创建
// 独立的地址空间才能使新程序正常运行
if (current_pcb->flags & PF_VFORK)
{
kdebug("proc:%d creating new mem space", current_pcb->pid);
// 分配新的内存空间分布结构体
struct mm_struct *new_mms = (struct mm_struct *)kmalloc(sizeof(struct mm_struct), 0);
memset(new_mms, 0, sizeof(struct mm_struct));
current_pcb->mm = new_mms;
uint64_t addr = 0x800000UL;
/*
unsigned long *tmp = phys_2_virt((unsigned long *)((unsigned long)get_CR3() & (~0xfffUL)) + ((addr >> PAGE_GDT_SHIFT) & 0x1ff));
// 分配顶层页表, 并设置顶层页表的物理地址
new_mms->pgd = (pml4t_t *)virt_2_phys(kmalloc(PAGE_4K_SIZE, 0));
unsigned long *virtual = kmalloc(PAGE_4K_SIZE, 0);
set_pml4t(tmp, mk_pml4t(virt_2_phys(virtual), PAGE_USER_PGT));
// 由于高2K部分为内核空间在接下来需要覆盖其数据因此不用清零
memset(phys_2_virt(new_mms->pgd), 0, PAGE_4K_SIZE / 2);
tmp = phys_2_virt((unsigned long *)(*tmp & (~0xfffUL)) + ((addr >> PAGE_1G_SHIFT) & 0x1ff));
virtual = kmalloc(PAGE_4K_SIZE, 0);
set_pdpt(tmp, mk_pdpt(virt_2_phys(virtual), PAGE_USER_DIR));
// 拷贝内核空间的页表指针
memcpy(phys_2_virt(new_mms->pgd) + 256, phys_2_virt(initial_proc[proc_current_cpu_id]) + 256, PAGE_4K_SIZE / 2);
}
tmp = phys_2_virt((unsigned long *)(*tmp & (~0xfffUL)) + ((addr >> PAGE_2M_SHIFT) & 0x1ff));
struct Page *p = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED);
set_pdt(tmp, mk_pdt(p->addr_phys, PAGE_USER_PAGE));
/**
* @todo: elf文件并映射对应的页
*
*/
// 映射1个2MB的物理页
unsigned long code_start_addr = 0x800000;
unsigned long stack_start_addr = 0xa00000;
flush_tlb();
*/
// mm_map_phys_addr_user(code_start_addr, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE);
mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, code_start_addr, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true);
mm_map_phys_addr_user(addr, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE);
process_switch_mm(current_pcb);
// 为用户态程序设置地址边界
if (!(current_pcb->flags & PF_KTHREAD))
current_pcb->addr_limit = USER_MAX_LINEAR_ADDR;
current_pcb->mm->code_addr_start = code_start_addr;
current_pcb->mm->code_addr_end = 0;
current_pcb->mm->data_addr_start = 0;
current_pcb->mm->data_addr_end = 0;
current_pcb->mm->rodata_addr_start = 0;
current_pcb->mm->rodata_addr_end = 0;
current_pcb->mm->bss_start = 0;
current_pcb->mm->bss_end = 0;
current_pcb->mm->brk_start = 0;
current_pcb->mm->brk_end = 0;
current_pcb->mm->stack_start = stack_start_addr;
// 关闭之前的文件描述符
process_exit_files(current_pcb);
// 清除进程的vfork标志位
current_pcb->flags &= ~PF_VFORK;
int fd_num = enter_syscall_int(SYS_OPEN, path, ATTR_READ_ONLY, 0, 0, 0, 0, 0, 0);
if (fd_num < 0)
return fd_num;
memset((void *)code_start_addr, 0, PAGE_2M_SIZE);
// 将程序代码拷贝到对应的内存中
memcpy((void *)0x800000, user_level_function, 1024);
int retval = enter_syscall_int(SYS_READ, fd_num, code_start_addr, PAGE_2M_SIZE, 0, 0, 0, 0, 0);
if (retval)
{
enter_syscall_int(SYS_CLOSE, fd_num, 0, 0, 0, 0, 0, 0, 0);
return retval;
}
retval = enter_syscall_int(SYS_CLOSE, fd_num, 0, 0, 0, 0, 0, 0, 0);
// kdebug("program copied!");
return 0;
@ -336,6 +430,13 @@ ul initial_kernel_thread(ul arg)
current_pcb->thread->rip = (ul)ret_from_system_call;
current_pcb->thread->rsp = (ul)current_pcb + STACK_SIZE - sizeof(struct pt_regs);
current_pcb->thread->fs = USER_DS|0x3;
current_pcb->thread->gs = USER_DS|0x3;
// 主动放弃内核线程身份
current_pcb->flags &= (~PF_KTHREAD);
// current_pcb->mm->pgd = kmalloc(PAGE_4K_SIZE, 0);
// memset((void*)current_pcb->mm->pgd, 0, PAGE_4K_SIZE);
@ -343,9 +444,11 @@ 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类似
// 加载用户态程序init.bin
__asm__ __volatile__("movq %1, %%rsp \n\t"
"pushq %2 \n\t"
"jmp do_execve \n\t" ::"D"(current_pcb->thread->rsp),
"S"("/init.bin"),
"m"(current_pcb->thread->rsp), "m"(current_pcb->thread->rip)
: "memory");
@ -437,9 +540,9 @@ void process_init()
for (int i = 256; i < 512; ++i)
{
uint64_t *tmp = idle_pml4t_vaddr + i;
if(*tmp==0)
if (*tmp == 0)
{
void* pdpt = kmalloc(PAGE_4K_SIZE,0);
void *pdpt = kmalloc(PAGE_4K_SIZE, 0);
memset(pdpt, 0, PAGE_4K_SIZE);
set_pml4t(tmp, mk_pml4t(virt_2_phys(pdpt), PAGE_KERNEL_PGT));
}
@ -671,16 +774,18 @@ uint64_t process_copy_files(uint64_t clone_flags, struct process_control_block *
*/
uint64_t process_exit_files(struct process_control_block *pcb)
{
// 与父进程共享文件描述符
if (pcb->flags & PF_VFORK)
return 0;
for (int i = 0; i < PROC_MAX_FD_NUM; ++i)
// 不与父进程共享文件描述符
if (!(pcb->flags & PF_VFORK))
{
if (pcb->fds[i] == NULL)
continue;
kfree(pcb->fds[i]);
for (int i = 0; i < PROC_MAX_FD_NUM; ++i)
{
if (pcb->fds[i] == NULL)
continue;
kfree(pcb->fds[i]);
}
}
// 清空当前进程的文件描述符列表
memset(pcb->fds, 0, sizeof(struct vfs_file_t *) * PROC_MAX_FD_NUM);
}
@ -697,7 +802,9 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
// 与父进程共享内存空间
if (clone_flags & CLONE_VM)
{
kdebug("copy_vm\t\t current_pcb->mm->pgd=%#018lx", current_pcb->mm->pgd);
pcb->mm = current_pcb->mm;
return retval;
}
@ -711,6 +818,8 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
// 分配顶层页表, 并设置顶层页表的物理地址
new_mms->pgd = (pml4t_t *)virt_2_phys(kmalloc(PAGE_4K_SIZE, 0));
// 由于高2K部分为内核空间在接下来需要覆盖其数据因此不用清零
memset(phys_2_virt(new_mms->pgd), 0, PAGE_4K_SIZE / 2);
// 拷贝内核空间的页表指针
memcpy(phys_2_virt(new_mms->pgd) + 256, phys_2_virt(initial_proc[proc_current_cpu_id]) + 256, PAGE_4K_SIZE / 2);
@ -859,4 +968,13 @@ uint64_t process_copy_thread(uint64_t clone_flags, struct process_control_block
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);
return 0;
}
/**
* @brief todo: 线
*
* @param pcb
*/
void process_exit_thread(struct process_control_block *pcb)
{
}

View File

@ -279,11 +279,12 @@ struct process_control_block *process_get_pcb(long pid);
* @param next pcb
*
*/
#define process_switch_mm(prev, next) \
do \
{ \
asm volatile("movq %0, %%cr3 \n\t" ::"r"(next->mm->pgd) \
: "memory"); \
#define process_switch_mm(next_pcb) \
do \
{ \
asm volatile("movq %0, %%cr3 \n\t" ::"r"(next_pcb->mm->pgd) \
: "memory"); \
flush_tlb(); \
} while (0)
// 获取当前cpu id

View File

@ -75,7 +75,7 @@ void sched_cfs()
}
}
// kdebug("before switch, next.rip = %#018lx\tnext->gs=%#018lx", proc->thread->rip, proc->thread->gs);
process_switch_mm(current_pcb, proc);
process_switch_mm(proc);
switch_proc(current_pcb, proc);
}
else // 不进行切换