From e2a59dbd433abe07260fe20d8c1bda7ca460f35c Mon Sep 17 00:00:00 2001 From: fslongjin Date: Tue, 31 May 2022 21:55:06 +0800 Subject: [PATCH] =?UTF-8?q?:new:=20exec=20=20(=E5=AD=98=E5=9C=A8bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 11 +++ kernel/exception/trap.c | 2 +- kernel/process/proc.S | 2 +- kernel/process/process.c | 133 ++++++++++++++++++++++++++-------- kernel/process/process.h | 43 ++++++++++- kernel/process/wait_queue.h | 2 +- kernel/syscall/syscall.c | 113 ++++++++++++++++++++++++++++- kernel/syscall/syscall_num.h | 4 + user/Makefile | 28 ++++--- user/apps/about/Makefile | 7 ++ user/apps/about/about.c | 7 ++ user/apps/shell/Makefile | 3 + user/apps/shell/cmd.c | 87 ++++++++++++++++------ user/apps/shell/shell.c | 14 +++- user/libs/libc/Makefile | 2 +- user/libs/libc/malloc.c | 4 +- user/libs/libc/stdlib.c | 11 +++ user/libs/libc/stdlib.h | 9 ++- user/libs/libc/sys/Makefile | 8 ++ user/libs/libc/sys/wait.c | 26 +++++++ user/libs/libc/sys/wait.h | 21 ++++++ user/libs/libc/unistd.c | 32 +++++--- user/libs/libc/unistd.h | 9 +++ user/libs/libsystem/syscall.h | 6 +- 24 files changed, 494 insertions(+), 90 deletions(-) create mode 100644 user/apps/about/Makefile create mode 100644 user/apps/about/about.c create mode 100644 user/libs/libc/sys/Makefile create mode 100644 user/libs/libc/sys/wait.c create mode 100644 user/libs/libc/sys/wait.h diff --git a/Makefile b/Makefile index 707d069f..c96d9dfe 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,17 @@ all: cd ..;\ done +.PHONY: user +user: + mkdir -p bin/user/ + mkdir -p bin/tmp/ + @list='./user'; for subdir in $$list; do \ + echo "make all in $$subdir";\ + cd $$subdir;\ + $(MAKE) all;\ + cd ..;\ + done + .PHONY: clean clean: @list='$(SUBDIRS)'; for subdir in $$list; do \ diff --git a/kernel/exception/trap.c b/kernel/exception/trap.c index 0c60bcd7..12d57d1e 100644 --- a/kernel/exception/trap.c +++ b/kernel/exception/trap.c @@ -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"); diff --git a/kernel/process/proc.S b/kernel/process/proc.S index afb7f9c7..0100be6f 100644 --- a/kernel/process/proc.S +++ b/kernel/process/proc.S @@ -31,4 +31,4 @@ ENTRY(kernel_thread_func) movq %rdx, %rdi callq *%rbx movq %rax, %rdi - callq process_thread_do_exit \ No newline at end of file + callq process_do_exit \ No newline at end of file diff --git a/kernel/process/process.c b/kernel/process/process.c index 1f88c972..dda49383 100644 --- a/kernel/process/process.c +++ b/kernel/process/process.c @@ -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(¤t_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; } diff --git a/kernel/process/process.h b/kernel/process/process.h index 9aa1e2c5..e13f8196 100644 --- a/kernel/process/process.h +++ b/kernel/process/process.h @@ -17,6 +17,7 @@ #include "ptrace.h" #include #include +#include // 进程最大可拥有的文件描述符数量 #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]; \ No newline at end of file +extern struct process_control_block *initial_proc[MAX_CPU_NUM]; diff --git a/kernel/process/wait_queue.h b/kernel/process/wait_queue.h index 3b3980be..4ee63efe 100644 --- a/kernel/process/wait_queue.h +++ b/kernel/process/wait_queue.h @@ -1,6 +1,6 @@ #pragma once #include -#include +// #include /** * @brief 信号量的等待队列 * diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index ec69274d..f2615c4c 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -9,6 +9,7 @@ #include #include #include +#include // 导出系统调用入口函数,定义在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(¤t_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}; diff --git a/kernel/syscall/syscall_num.h b/kernel/syscall/syscall_num.h index b628dcf8..728815c0 100644 --- a/kernel/syscall/syscall_num.h +++ b/kernel/syscall/syscall_num.h @@ -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的系统调用 \ No newline at end of file diff --git a/user/Makefile b/user/Makefile index 74a4d2f4..747a3a2f 100644 --- a/user/Makefile +++ b/user/Makefile @@ -13,31 +13,29 @@ CFLAGS := $(GLOBAL_CFLAGS) -I $(shell pwd)/libs current_CFLAGS := $(CFLAGS) all: + $(shell if [ ! -e $(tmp_output_dir) ];then mkdir -p $(tmp_output_dir); fi) + $(shell if [ ! -e $(output_dir) ];then mkdir -p $(output_dir); fi) + @list='$(user_sub_dirs)'; for subdir in $$list; do \ + echo "make all in $$subdir";\ + cd $$subdir;\ + $(MAKE) all CFLAGS="$(CFLAGS)" tmp_output_dir="$(tmp_output_dir)" output_dir="$(output_dir)" sys_libs_dir="$(shell pwd)/libs";\ + cd ..;\ + done + +# 系统库 +sys_api_lib: + @list='./libs'; for subdir in $$list; do \ echo "make all in $$subdir";\ cd $$subdir;\ $(MAKE) all CFLAGS="$(CFLAGS)";\ cd ..;\ done - - $(shell if [ ! -e $(tmp_output_dir) ];then mkdir -p $(tmp_output_dir); fi) - $(shell if [ ! -e $(output_dir) ];then mkdir -p $(output_dir); fi) - -# $(MAKE) sys_api_lib - $(MAKE) shell -# objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary sys_api_lib $(ROOT_PATH)/bin/user/init.bin -#objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O elf64-x86-64 sys_api_lib $(ROOT_PATH)/bin/user/init.bin - -sys_api_lib: - - ld -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/sys_api_lib $(shell find ./libs -name "*.o") +# ld -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/sys_api_lib $(shell find ./libs -name "*.o") #ld -b elf64-x86-64 -z muldefs -o sys_api_lib init.o $(shell find . -name "*.o") -T init.lds -shell: - ld -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/shell $(shell find ./apps/shell -name "*.o") $(shell find ./libs -name "*.o") -T ./apps/shell/shell.lds - objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/shell $(output_dir)/shell.elf clean: rm -rf $(GARBAGE) \ No newline at end of file diff --git a/user/apps/about/Makefile b/user/apps/about/Makefile new file mode 100644 index 00000000..c6d8ee63 --- /dev/null +++ b/user/apps/about/Makefile @@ -0,0 +1,7 @@ +all: about.o + + ld -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/about $(shell find . -name "*.o") $(shell find $(sys_libs_dir) -name "*.o") -T shell.lds + + objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/about $(output_dir)/about.elf +about.o: about.c + gcc $(CFLAGS) -c about.c -o about.o diff --git a/user/apps/about/about.c b/user/apps/about/about.c new file mode 100644 index 00000000..5ad17bb2 --- /dev/null +++ b/user/apps/about/about.c @@ -0,0 +1,7 @@ +#include + +int main() +{ + printf("Hello World!\n"); + while(1); +} \ No newline at end of file diff --git a/user/apps/shell/Makefile b/user/apps/shell/Makefile index c2035788..97d5e22e 100644 --- a/user/apps/shell/Makefile +++ b/user/apps/shell/Makefile @@ -1,5 +1,8 @@ all: shell.o cmd.o cmd_help.o + ld -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/shell $(shell find . -name "*.o") $(shell find $(sys_libs_dir) -name "*.o") -T shell.lds + + objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/shell $(output_dir)/shell.elf shell.o: shell.c gcc $(CFLAGS) -c shell.c -o shell.o diff --git a/user/apps/shell/cmd.c b/user/apps/shell/cmd.c index 2bfd6ad3..58555964 100644 --- a/user/apps/shell/cmd.c +++ b/user/apps/shell/cmd.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "cmd_help.h" @@ -36,6 +37,36 @@ struct built_in_cmd_t shell_cmds[] = // 总共的内建命令数量 const static int total_built_in_cmd_num = sizeof(shell_cmds) / sizeof(struct built_in_cmd_t); +/** + * @brief 将cwd与文件名进行拼接,得到最终的文件绝对路径 + * + * @param filename 文件名 + * @param result_path_len 结果字符串的大小 + * @return char* 结果字符串 + */ +static char *get_target_filepath(const char *filename, int *result_path_len) +{ + int cwd_len = strlen(shell_current_path); + + // 计算文件完整路径的长度 + *result_path_len = cwd_len + strlen(filename); + + char *file_path = (char *)malloc(*result_path_len + 2); + + memset(file_path, 0, *result_path_len + 2); + + strcpy(file_path, shell_current_path); + + // 在文件路径中加入斜杠 + if (cwd_len > 1) + file_path[cwd_len] = '/'; + + // 拼接完整路径 + strcat(file_path, filename); + + return file_path; +} + /** * @brief 寻找对应的主命令编号 * @@ -230,7 +261,7 @@ int shell_cmd_ls(int argc, char **argv) printf("\n"); closedir(dir); - if (argc > 1) + if (argv != NULL) free(argv); return 0; @@ -247,7 +278,7 @@ int shell_cmd_pwd(int argc, char **argv) { if (shell_current_path) printf("%s\n", shell_current_path); - if (argc > 1) + if (argv != NULL) free(argv); } @@ -260,23 +291,8 @@ int shell_cmd_pwd(int argc, char **argv) */ int shell_cmd_cat(int argc, char **argv) { - int cwd_len = strlen(shell_current_path); - - // 计算文件完整路径的长度 - int file_path_len = cwd_len + strlen(argv[1]); - - char *file_path = (char *)malloc(file_path_len + 2); - - memset(file_path, 0, file_path_len + 2); - - strcpy(file_path, shell_current_path); - - // 在文件路径中加入斜杠 - if (cwd_len > 1) - file_path[cwd_len] = '/'; - - // 拼接完整路径 - strcat(file_path, argv[1]); + int path_len = 0; + char *file_path = get_target_filepath(argv[1], &path_len); // 打开文件 int fd = open(file_path, 0); @@ -298,6 +314,8 @@ int shell_cmd_cat(int argc, char **argv) close(fd); free(buf); + if (argv != NULL) + free(argv); } /** @@ -347,9 +365,36 @@ int shell_cmd_rmdir(int argc, char **argv) {} * @param argv * @return int */ +int shell_cmd_exec(int argc, char **argv) +{ + pid_t pid = fork(); + int retval = 0; + printf(" pid=%d \n",pid); -// todo: -int shell_cmd_exec(int argc, char **argv) {} + while(1); + if (pid == 0) + { + printf("child proc\n"); + // 子进程 + int path_len = 0; + char *file_path = get_target_filepath(argv[1], &path_len); + printf("before execv, path=%s\n", file_path); + execv(file_path, argv); + free(argv); + while(1); + exit(0); + } + else + { + printf("parent process wait for pid:[ %d ]\n", pid); + while(1); + waitpid(pid, &retval, 0); + printf("parent process wait pid [ %d ], exit code=%d\n", pid, retval); + free(argv); + } + + while(1); +} /** * @brief 重启命令 diff --git a/user/apps/shell/shell.c b/user/apps/shell/shell.c index 070adbc1..4a4d5c9a 100644 --- a/user/apps/shell/shell.c +++ b/user/apps/shell/shell.c @@ -37,13 +37,22 @@ int parse_command(char *buf, int *argc, char ***argv); * * @param kb_fd 键盘文件描述符 */ -static void main_loop(int kb_fd) +void main_loop(int kb_fd) { + unsigned char input_buffer[INPUT_BUFFER_SIZE] = {0}; + sbrk(24); + pid_t pid = fork(); + int retval = 0; + + + while (1) + printf(" @pid=%d ", pid); // 初始化当前工作目录的路径 shell_current_path = (char *)malloc(3); - memset(shell_current_path, 0, 3); + + memset(shell_current_path, 0, 3); shell_current_path[0] = '/'; shell_current_path[1] = '\0'; @@ -54,6 +63,7 @@ static void main_loop(int kb_fd) char **argv; printf("[DragonOS] %s # ", shell_current_path); + memset(input_buffer, 0, INPUT_BUFFER_SIZE); // 循环读取每一行到buffer diff --git a/user/libs/libc/Makefile b/user/libs/libc/Makefile index 689f64bb..1b7b1541 100644 --- a/user/libs/libc/Makefile +++ b/user/libs/libc/Makefile @@ -2,7 +2,7 @@ all: libc CFLAGS += -I . -libc_sub_dirs=math +libc_sub_dirs=math sys libc: unistd.o fcntl.o malloc.o errno.o printf.o stdlib.o ctype.o string.o dirent.o diff --git a/user/libs/libc/malloc.c b/user/libs/libc/malloc.c index 8129ccc1..3546d4dc 100644 --- a/user/libs/libc/malloc.c +++ b/user/libs/libc/malloc.c @@ -138,7 +138,7 @@ static int malloc_enlarge(int64_t size) } int64_t free_space = brk_max_addr - brk_managed_addr; - + // printf("size=%ld\tfree_space=%ld\n", size, free_space); if (free_space < size) // 现有堆空间不足 { if (sbrk(size - free_space) != (void *)(-1)) @@ -148,6 +148,8 @@ static int malloc_enlarge(int64_t size) put_string("malloc_enlarge(): no_mem\n", COLOR_YELLOW, COLOR_BLACK); return -ENOMEM; } + + // printf("brk max addr = %#018lx\n", brk_max_addr); } // 扩展管理的堆空间 diff --git a/user/libs/libc/stdlib.c b/user/libs/libc/stdlib.c index a6af1878..ed8a5c14 100644 --- a/user/libs/libc/stdlib.c +++ b/user/libs/libc/stdlib.c @@ -1,6 +1,7 @@ #include #include #include +#include int abs(int i) { @@ -43,4 +44,14 @@ int atoi(const char *str) } return neg ? n : -n; +} + +/** + * @brief 退出进程 + * + * @param status + */ +void exit(int status) +{ + syscall_invoke(SYS_EXIT, status, 0, 0, 0, 0, 0, 0, 0); } \ No newline at end of file diff --git a/user/libs/libc/stdlib.h b/user/libs/libc/stdlib.h index 66f49d7e..5d96bd8b 100644 --- a/user/libs/libc/stdlib.h +++ b/user/libs/libc/stdlib.h @@ -32,4 +32,11 @@ long long llabs(long long i); * @param str * @return int */ -int atoi(const char * str); \ No newline at end of file +int atoi(const char * str); + +/** + * @brief 退出进程 + * + * @param status + */ +void exit(int status); \ No newline at end of file diff --git a/user/libs/libc/sys/Makefile b/user/libs/libc/sys/Makefile new file mode 100644 index 00000000..27d502da --- /dev/null +++ b/user/libs/libc/sys/Makefile @@ -0,0 +1,8 @@ + +all: wait.o + +CFLAGS += -I . + + +wait.o: wait.c + gcc $(CFLAGS) -c wait.c -o wait.o diff --git a/user/libs/libc/sys/wait.c b/user/libs/libc/sys/wait.c new file mode 100644 index 00000000..07a5c8c9 --- /dev/null +++ b/user/libs/libc/sys/wait.c @@ -0,0 +1,26 @@ +#include "wait.h" +#include + +/** + * @brief 等待所有子进程退出 + * + * @param stat_loc 返回的子进程结束状态 + * @return pid_t + */ +pid_t wait(int *stat_loc) +{ + return waitpid((pid_t)(-1), stat_loc, 0); +} + +/** + * @brief 等待指定pid的子进程退出 + * + * @param pid 子进程的pid + * @param stat_loc 返回的子进程结束状态 + * @param options 额外的控制选项 + * @return pid_t + */ +pid_t waitpid(pid_t pid, int *stat_loc, int options) +{ + return (pid_t)syscall_invoke(SYS_WAIT4, (uint64_t)pid, (uint64_t)stat_loc, options, 0, 0, 0, 0, 0); +} \ No newline at end of file diff --git a/user/libs/libc/sys/wait.h b/user/libs/libc/sys/wait.h new file mode 100644 index 00000000..7a5c3615 --- /dev/null +++ b/user/libs/libc/sys/wait.h @@ -0,0 +1,21 @@ +#pragma once + +#include "types.h" + +/** + * @brief 等待所有子进程退出 + * + * @param stat_loc 返回的子进程结束状态 + * @return pid_t + */ +pid_t wait(int *stat_loc); + +/** + * @brief 等待指定pid的子进程退出 + * + * @param pid 子进程的pid + * @param stat_loc 返回的子进程结束状态 + * @param options 额外的控制选项 + * @return pid_t + */ +pid_t waitpid(pid_t pid, int *stat_loc, int options); diff --git a/user/libs/libc/unistd.c b/user/libs/libc/unistd.c index db5db22c..7d07a4e0 100644 --- a/user/libs/libc/unistd.c +++ b/user/libs/libc/unistd.c @@ -123,16 +123,26 @@ int64_t chdir(char *dest_path) } else { - int retval = syscall_invoke(SYS_CHDIR, (uint64_t)dest_path, 0,0,0,0,0,0,0); - if(retval == 0) - { - errno = 0; - return 0; - } - else - { - errno = retval; - return -1; - } + return syscall_invoke(SYS_CHDIR, (uint64_t)dest_path, 0, 0, 0, 0, 0, 0, 0); } +} + +/** + * @brief 执行新的程序 + * + * @param path 文件路径 + * @param argv 参数列表 + * @return int + */ +int execv(const char *path, char *const argv[]) +{ + if (path == NULL) + { + errno = -ENOENT; + return -1; + } + int retval = syscall_invoke(SYS_EXECVE, (uint64_t)path, (uint64_t)argv, 0, 0, 0, 0, 0, 0); + if(retval != 0) + return -1; + else return 0; } \ No newline at end of file diff --git a/user/libs/libc/unistd.h b/user/libs/libc/unistd.h index de8ff3f6..5a385ff1 100644 --- a/user/libs/libc/unistd.h +++ b/user/libs/libc/unistd.h @@ -80,3 +80,12 @@ void *sbrk(int64_t increment); * @return int64_t 成功:0,失败:负值(错误码) */ int64_t chdir(char *dest_path); + +/** + * @brief 执行新的程序 + * + * @param path 文件路径 + * @param argv 参数列表 + * @return int + */ +int execv(const char* path, char * const argv[]); diff --git a/user/libs/libsystem/syscall.h b/user/libs/libsystem/syscall.h index 5ffd286e..3e0ec04b 100644 --- a/user/libs/libsystem/syscall.h +++ b/user/libs/libsystem/syscall.h @@ -14,9 +14,13 @@ #define SYS_VFORK 8 #define SYS_BRK 9 #define SYS_SBRK 10 -#define SYS_REBOOT 11 + +#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 // 进程退出 /** * @brief 用户态系统调用函数