1 /** 2 * @file process.h 3 * @author longjin 4 * @brief 进程 5 * @date 2022-01-29 6 * 7 * @copyright Copyright (c) 2022 8 * 9 */ 10 11 #pragma once 12 #include "ptrace.h" 13 #include <common/cpu.h> 14 #include <common/errno.h> 15 #include <common/glib.h> 16 #include <common/wait_queue.h> 17 #include <filesystem/VFS/VFS.h> 18 #include <mm/mm-types.h> 19 #include <syscall/syscall.h> 20 21 #include <asm/current.h> 22 23 #include "proc-types.h" 24 25 // 设置初始进程的PCB 26 #define INITIAL_PROC(proc) \ 27 { \ 28 .state = PROC_UNINTERRUPTIBLE, .flags = PF_KTHREAD, .preempt_count = 0, .signal = 0, .cpu_id = 0, \ 29 .mm = &initial_mm, .thread = &initial_thread, .addr_limit = 0xffffffffffffffff, .pid = 0, .priority = 2, \ 30 .virtual_runtime = 0, .fds = {0}, .next_pcb = &proc, .prev_pcb = &proc, .parent_pcb = &proc, .exit_code = 0, \ 31 .wait_child_proc_exit = 0, .worker_private = NULL, .policy = SCHED_NORMAL \ 32 } 33 34 /** 35 * @brief 任务状态段结构体 36 * 37 */ 38 39 // 设置初始进程的tss 40 #define INITIAL_TSS \ 41 { \ 42 .reserved0 = 0, .rsp0 = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), \ 43 .rsp1 = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), \ 44 .rsp2 = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), .reserved1 = 0, .ist1 = 0xffff800000007c00, \ 45 .ist2 = 0xffff800000007c00, .ist3 = 0xffff800000007c00, .ist4 = 0xffff800000007c00, \ 46 .ist5 = 0xffff800000007c00, .ist6 = 0xffff800000007c00, .ist7 = 0xffff800000007c00, .reserved2 = 0, \ 47 .reserved3 = 0, .io_map_base_addr = 0 \ 48 } 49 50 #define GET_CURRENT_PCB \ 51 "movq %rsp, %rbx \n\t" \ 52 "andq $-32768, %rbx\n\t" 53 54 /** 55 * @brief 切换进程上下文 56 * 先把rbp和rax保存到栈中,然后将rsp和rip保存到prev的thread结构体中 57 * 然后调用__switch_to切换栈,配置其他信息,最后恢复下一个进程的rax rbp。 58 */ 59 60 #define switch_proc(prev, next) \ 61 do \ 62 { \ 63 __asm__ __volatile__("pushq %%rbp \n\t" \ 64 "pushq %%rax \n\t" \ 65 "movq %%rsp, %0 \n\t" \ 66 "movq %2, %%rsp \n\t" \ 67 "leaq switch_proc_ret_addr(%%rip), %%rax \n\t" \ 68 "movq %%rax, %1 \n\t" \ 69 "pushq %3 \n\t" \ 70 "jmp __switch_to \n\t" \ 71 "switch_proc_ret_addr: \n\t" \ 72 "popq %%rax \n\t" \ 73 "popq %%rbp \n\t" \ 74 : "=m"(prev->thread->rsp), "=m"(prev->thread->rip) \ 75 : "m"(next->thread->rsp), "m"(next->thread->rip), "D"(prev), "S"(next) \ 76 : "memory"); \ 77 } while (0) 78 79 /** 80 * @brief 初始化系统的第一个进程 81 * 82 */ 83 void process_init(); 84 85 /** 86 * @brief fork当前进程 87 * 88 * @param regs 新的寄存器值 89 * @param clone_flags 克隆标志 90 * @param stack_start 堆栈开始地址 91 * @param stack_size 堆栈大小 92 * @return unsigned long 93 */ 94 unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned long stack_start, 95 unsigned long stack_size); 96 97 /** 98 * @brief 根据pid获取进程的pcb。存在对应的pcb时,返回对应的pcb的指针,否则返回NULL 99 * 100 * @param pid 101 * @return struct process_control_block* 102 */ 103 struct process_control_block *process_find_pcb_by_pid(pid_t pid); 104 105 /** 106 * @brief 将进程加入到调度器的就绪队列中 107 * 108 * @param pcb 进程的pcb 109 */ 110 int process_wakeup(struct process_control_block *pcb); 111 112 /** 113 * @brief 将进程加入到调度器的就绪队列中,并标志当前进程需要被调度 114 * 115 * @param pcb 进程的pcb 116 */ 117 int process_wakeup_immediately(struct process_control_block *pcb); 118 119 /** 120 * @brief 使当前进程去执行新的代码 121 * 122 * @param regs 当前进程的寄存器 123 * @param path 可执行程序的路径 124 * @param argv 参数列表 125 * @param envp 环境变量 126 * @return ul 错误码 127 */ 128 ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[]); 129 130 /** 131 * @brief 释放进程的页表 132 * 133 * @param pcb 要被释放页表的进程 134 * @return uint64_t 135 */ 136 uint64_t process_exit_mm(struct process_control_block *pcb); 137 138 /** 139 * @brief 进程退出时执行的函数 140 * 141 * @param code 返回码 142 * @return ul 143 */ 144 ul process_do_exit(ul code); 145 146 /** 147 * @brief 当子进程退出后向父进程发送通知 148 * 149 */ 150 void process_exit_notify(); 151 152 /** 153 * @brief 初始化内核进程 154 * 155 * @param fn 目标程序的地址 156 * @param arg 向目标程序传入的参数 157 * @param flags 158 * @return int 159 */ 160 161 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); 162 163 int process_fd_alloc(struct vfs_file_t *file); 164 165 int process_release_pcb(struct process_control_block *pcb); 166 167 /** 168 * @brief 切换页表 169 * @param prev 前一个进程的pcb 170 * @param next 下一个进程的pcb 171 * 172 */ 173 #define process_switch_mm(next_pcb) \ 174 do \ 175 { \ 176 asm volatile("movq %0, %%cr3 \n\t" ::"r"(next_pcb->mm->pgd) : "memory"); \ 177 } while (0) 178 // flush_tlb(); 179 180 // 获取当前cpu id 181 #define proc_current_cpu_id (current_pcb->cpu_id) 182 183 extern unsigned long head_stack_start; // 导出内核层栈基地址(定义在head.S) 184 extern ul _stack_start; 185 extern void ret_from_intr(void); // 导出从中断返回的函数(定义在entry.S) 186 187 extern struct tss_struct initial_tss[MAX_CPU_NUM]; 188 extern struct mm_struct initial_mm; 189 extern struct thread_struct initial_thread; 190 extern union proc_union initial_proc_union; 191 extern struct process_control_block *initial_proc[MAX_CPU_NUM]; 192 193 /** 194 * @brief 给pcb设置名字 195 * 196 * @param pcb 需要设置名字的pcb 197 * @param pcb_name 保存名字的char数组 198 */ 199 void process_set_pcb_name(struct process_control_block *pcb, const char *pcb_name); 200