mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-10 08:06:48 +00:00
完善execve,使其能加载用户程序文件
This commit is contained in:
parent
1801ddffbd
commit
099b24539a
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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);
|
@ -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)
|
||||
{
|
||||
}
|
@ -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
|
||||
|
@ -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 // 不进行切换
|
||||
|
Loading…
x
Reference in New Issue
Block a user