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 extern void process_exit_thread(struct process_control_block *pcb);
26 extern uint64_t process_exit_files(struct process_control_block *pcb);
27 
28 /**
29  * @brief 任务状态段结构体
30  *
31  */
32 
33 // 设置初始进程的tss
34 #define INITIAL_TSS                                                                                                    \
35     {                                                                                                                  \
36         .reserved0 = 0, .rsp0 = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)),                              \
37         .rsp1 = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)),                                              \
38         .rsp2 = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), .reserved1 = 0, .ist1 = 0xffff800000007c00,  \
39         .ist2 = 0xffff800000007c00, .ist3 = 0xffff800000007c00, .ist4 = 0xffff800000007c00,                            \
40         .ist5 = 0xffff800000007c00, .ist6 = 0xffff800000007c00, .ist7 = 0xffff800000007c00, .reserved2 = 0,            \
41         .reserved3 = 0, .io_map_base_addr = 0                                                                          \
42     }
43 
44 #define GET_CURRENT_PCB                                                                                                \
45     "movq %rsp, %rbx \n\t"                                                                                             \
46     "andq $-32768, %rbx\n\t"
47 
48 /**
49  * @brief 切换进程上下文
50  * 先把rbp和rax保存到栈中,然后将rsp和rip保存到prev的thread结构体中
51  * 然后调用__switch_to切换栈,配置其他信息,最后恢复下一个进程的rax rbp。
52  */
53 
54 #define switch_to(prev, next)                                                                                          \
55     do                                                                                                                 \
56     {                                                                                                                  \
57         __asm__ __volatile__("pushq	%%rbp	\n\t"                                                                        \
58                              "pushq	%%rax	\n\t"                                                                        \
59                              "movq	%%rsp,	%0	\n\t"                                                                     \
60                              "movq	%2,	%%rsp	\n\t"                                                                     \
61                              "leaq	2f(%%rip),	%%rax	\n\t"                                                              \
62                              "movq	%%rax,	%1	\n\t"                                                                     \
63                              "pushq	%3		\n\t"                                                                          \
64                              "jmp	__switch_to	\n\t"                                                                    \
65                              "2:	\n\t"                                                                                 \
66                              "popq	%%rax	\n\t"                                                                         \
67                              "popq	%%rbp	\n\t"                                                                         \
68                              : "=m"(prev->thread->rsp), "=m"(prev->thread->rip)                                        \
69                              : "m"(next->thread->rsp), "m"(next->thread->rip), "D"(prev), "S"(next)                    \
70                              : "memory", "rax");                                                                       \
71     } while (0)
72 
73 /**
74  * @brief 初始化系统的第一个进程
75  *
76  */
77 void process_init();
78 
79 /**
80  * @brief fork当前进程
81  *
82  * @param regs 新的寄存器值
83  * @param clone_flags 克隆标志
84  * @param stack_start 堆栈开始地址
85  * @param stack_size 堆栈大小
86  * @return unsigned long
87  */
88 unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned long stack_start,
89                       unsigned long stack_size);
90 
91 /**
92  * @brief 根据pid获取进程的pcb。存在对应的pcb时,返回对应的pcb的指针,否则返回NULL
93  * 当进程管理模块拥有pcblist_lock之后,调用本函数之前,应当对其加锁
94  * @param pid
95  * @return struct process_control_block*
96  */
97 struct process_control_block *process_find_pcb_by_pid(pid_t pid);
98 
99 /**
100  * @brief 将进程加入到调度器的就绪队列中
101  *
102  * @param pcb 进程的pcb
103  *
104  * @return 如果进程被成功唤醒,则返回1,如果进程正在运行,则返回0.如果pcb为NULL,则返回-EINVAL
105  */
106 int process_wakeup(struct process_control_block *pcb);
107 
108 /**
109  * @brief 将进程加入到调度器的就绪队列中,并标志当前进程需要被调度
110  *
111  * @param pcb 进程的pcb
112  */
113 int process_wakeup_immediately(struct process_control_block *pcb);
114 
115 /**
116  * @brief 使当前进程去执行新的代码
117  *
118  * @param regs 当前进程的寄存器
119  * @param path 可执行程序的路径
120  * @param argv 参数列表
121  * @param envp 环境变量
122  * @return ul 错误码
123  */
124 ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[]);
125 
126 /**
127  * @brief 释放进程的页表
128  *
129  * @param pcb 要被释放页表的进程
130  * @return uint64_t
131  */
132 uint64_t process_exit_mm(struct process_control_block *pcb);
133 
134 /**
135  * @brief 进程退出时执行的函数
136  *
137  * @param code 返回码
138  * @return ul
139  */
140 ul process_do_exit(ul code);
141 
142 /**
143  * @brief 当子进程退出后向父进程发送通知
144  *
145  */
146 void process_exit_notify();
147 
148 /**
149  * @brief 初始化内核进程
150  *
151  * @param fn 目标程序的地址
152  * @param arg 向目标程序传入的参数
153  * @param flags
154  * @return int
155  */
156 
157 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
158 
159 int process_fd_alloc(struct vfs_file_t *file);
160 
161 int process_release_pcb(struct process_control_block *pcb);
162 
163 /**
164  * @brief 切换页表
165  * @param prev 前一个进程的pcb
166  * @param next 下一个进程的pcb
167  *
168  */
169 #define process_switch_mm(next_pcb)                                                                                    \
170     do                                                                                                                 \
171     {                                                                                                                  \
172         asm volatile("movq %0, %%cr3	\n\t" ::"r"(next_pcb->mm->pgd) : "memory");                                    \
173     } while (0)
174 // flush_tlb();
175 
176 // 获取当前cpu id
177 #define proc_current_cpu_id (current_pcb->cpu_id)
178 
179 extern unsigned long head_stack_start; // 导出内核层栈基地址(定义在head.S
180 extern ul _stack_start;
181 extern void ret_from_intr(void); // 导出从中断返回的函数(定义在entry.S
182 
183 extern struct tss_struct initial_tss[MAX_CPU_NUM];
184 extern struct mm_struct initial_mm;
185 extern struct thread_struct initial_thread;
186 extern union proc_union initial_proc_union;
187 extern struct process_control_block *initial_proc[MAX_CPU_NUM];
188 
189 /**
190  * @brief 给pcb设置名字
191  *
192  * @param pcb 需要设置名字的pcb
193  * @param pcb_name 保存名字的char数组
194  */
195 void process_set_pcb_name(struct process_control_block *pcb, const char *pcb_name);
196 
197 /**
198  * @brief 判断进程是否已经停止
199  *
200  * hint: 本函数在rust中实现,请参考rust版本的注释
201  *
202  * @param pcb 目标pcb
203  * @return true
204  * @return false
205  */
206 extern bool process_is_stopped(struct process_control_block *pcb);
207 
208 /**
209  * @brief 尝试唤醒指定的进程。
210  * 本函数的行为:If (@_state & @pcb->state) @pcb->state = TASK_RUNNING.
211  *
212  * hint: 本函数在rust中实现,请参考rust版本的注释
213  */
214 extern int process_try_to_wake_up(struct process_control_block *_pcb, uint64_t _state, int32_t _wake_flags);
215 
216 /** @brief 当进程,满足 (@state & @pcb->state)时,唤醒进程,并设置: @pcb->state = TASK_RUNNING.
217  *
218  * hint: 本函数在rust中实现,请参考rust版本的注释
219  * @return true 唤醒成功
220  * @return false 唤醒失败
221  */
222 extern int process_wake_up_state(struct process_control_block *pcb, uint64_t state);
223 void __switch_to(struct process_control_block *prev, struct process_control_block *next);
224 
225 void process_open_stdio(struct process_control_block * pcb);