Răsfoiți Sursa

:new: exec (存在bug

fslongjin 2 ani în urmă
părinte
comite
e2a59dbd43

+ 11 - 0
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 \

+ 1 - 1
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");

+ 1 - 1
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		  
+    callq	process_do_exit		  

+ 103 - 30
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(&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;
 }
 

+ 41 - 2
kernel/process/process.h

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

+ 1 - 1
kernel/process/wait_queue.h

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

+ 111 - 2
kernel/syscall/syscall.c

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

+ 4 - 0
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的系统调用

+ 13 - 15
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)";\
+    		 $(MAKE) all CFLAGS="$(CFLAGS)" tmp_output_dir="$(tmp_output_dir)" output_dir="$(output_dir)" sys_libs_dir="$(shell pwd)/libs";\
     		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
+	done	
 
+# 系统库
 sys_api_lib:
+	@list='./libs'; for subdir in $$list; do \
+    		echo "make all in $$subdir";\
+    		cd $$subdir;\
+    		 $(MAKE) all CFLAGS="$(CFLAGS)";\
+    		cd ..;\
+	done
 
-	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)
 	

+ 7 - 0
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

+ 7 - 0
user/apps/about/about.c

@@ -0,0 +1,7 @@
+#include <libc/stdio.h>
+
+int main()
+{
+    printf("Hello World!\n");
+    while(1);
+}

+ 3 - 0
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
 

+ 66 - 21
user/apps/shell/cmd.c

@@ -9,6 +9,7 @@
 #include <libc/stdlib.h>
 #include <libc/fcntl.h>
 #include <libc/dirent.h>
+#include <libc/sys/wait.h>
 
 #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 重启命令

+ 12 - 2
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

+ 1 - 1
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

+ 3 - 1
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);
     }
 
     // 扩展管理的堆空间

+ 11 - 0
user/libs/libc/stdlib.c

@@ -1,6 +1,7 @@
 #include <libc/unistd.h>
 #include <libc/stdlib.h>
 #include <libc/ctype.h>
+#include <libsystem/syscall.h>
 
 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);
 }

+ 8 - 1
user/libs/libc/stdlib.h

@@ -32,4 +32,11 @@ long long llabs(long long i);
  * @param str 
  * @return int 
  */
-int atoi(const char * str);
+int atoi(const char * str);
+
+/**
+ * @brief 退出进程
+ * 
+ * @param status 
+ */
+void exit(int status);

+ 8 - 0
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

+ 26 - 0
user/libs/libc/sys/wait.c

@@ -0,0 +1,26 @@
+#include "wait.h"
+#include <libsystem/syscall.h>
+
+/**
+ * @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);
+}

+ 21 - 0
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);

+ 21 - 11
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;
 }

+ 9 - 0
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[]);

+ 5 - 1
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 用户态系统调用函数