1 #include "process.h"
2 
3 #include <DragonOS/signal.h>
4 #include <common/compiler.h>
5 #include <common/completion.h>
6 #include <common/elf.h>
7 #include <common/kprint.h>
8 #include <common/kthread.h>
9 #include <common/lz4.h>
10 #include <common/printk.h>
11 #include <common/spinlock.h>
12 #include <common/stdio.h>
13 #include <common/string.h>
14 #include <common/sys/wait.h>
15 #include <common/time.h>
16 #include <common/unistd.h>
17 #include <debug/bug.h>
18 #include <debug/traceback/traceback.h>
19 #include <driver/disk/ahci/ahci.h>
20 #include <driver/video/video.h>
21 #include <driver/virtio/virtio.h>
22 #include <exception/gate.h>
23 #include <ktest/ktest.h>
24 #include <mm/mmio.h>
25 #include <mm/slab.h>
26 #include <sched/sched.h>
27 #include <syscall/syscall.h>
28 #include <syscall/syscall_num.h>
29 extern int __rust_demo_func();
30 // #pragma GCC push_options
31 // #pragma GCC optimize("O0")
32 
33 spinlock_t process_global_pid_write_lock; // 增加pid的写锁
34 long process_global_pid = 1;              // 系统中最大的pid
35 
36 extern void system_call(void);
37 extern void kernel_thread_func(void);
38 extern void rs_procfs_unregister_pid(uint64_t);
39 
40 ul _stack_start; // initial proc的栈基地址(虚拟地址)
41 extern struct signal_struct INITIAL_SIGNALS;
42 extern struct sighand_struct INITIAL_SIGHAND;
43 
44 extern void process_exit_sighand(struct process_control_block *pcb);
45 extern void process_exit_signal(struct process_control_block *pcb);
46 extern void initial_proc_init_signal(struct process_control_block *pcb);
47 extern void rs_process_exit_fpstate(struct process_control_block *pcb);
48 extern void rs_drop_address_space(struct process_control_block *pcb);
49 extern int process_init_files();
50 extern int rs_init_stdio();
51 extern uint64_t rs_do_execve(const char *filename, const char *const argv[], const char *const envp[], struct pt_regs *regs);
52 extern uint64_t rs_exec_init_process(struct pt_regs *regs);
53 
54 // 设置初始进程的PCB
55 #define INITIAL_PROC(proc)                                                                                           \
56     {                                                                                                                \
57         .state = PROC_UNINTERRUPTIBLE, .flags = PF_KTHREAD, .preempt_count = 0, .signal = 0, .cpu_id = 0,            \
58         .thread = &initial_thread, .addr_limit = 0xffffffffffffffff, .pid = 0, .priority = 2,                        \
59         .virtual_runtime = 0, .fds = {0}, .next_pcb = &proc, .prev_pcb = &proc, .parent_pcb = &proc, .exit_code = 0, \
60         .wait_child_proc_exit = 0, .worker_private = NULL, .policy = SCHED_NORMAL, .sig_blocked = 0,                 \
61         .signal = &INITIAL_SIGNALS, .sighand = &INITIAL_SIGHAND, .address_space = NULL                               \
62     }
63 
64 struct thread_struct initial_thread = {
65     .rbp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)),
66     .rsp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)),
67     .fs = KERNEL_DS,
68     .gs = KERNEL_DS,
69     .cr2 = 0,
70     .trap_num = 0,
71     .err_code = 0,
72 };
73 
74 // 初始化 初始进程的union ,并将其链接到.data.init_proc段内
75 union proc_union initial_proc_union
76     __attribute__((__section__(".data.init_proc_union"))) = {INITIAL_PROC(initial_proc_union.pcb)};
77 
78 struct process_control_block *initial_proc[MAX_CPU_NUM] = {&initial_proc_union.pcb, 0};
79 
80 // 为每个核心初始化初始进程的tss
81 struct tss_struct initial_tss[MAX_CPU_NUM] = {[0 ... MAX_CPU_NUM - 1] = INITIAL_TSS};
82 
83 /**
84  * @brief 回收进程的所有文件描述符
85  *
86  * @param pcb 要被回收的进程的pcb
87  * @return uint64_t
88  */
89 extern int process_exit_files(struct process_control_block *pcb);
90 
91 /**
92  * @brief 释放进程的页表
93  *
94  * @param pcb 要被释放页表的进程
95  * @return uint64_t
96  */
97 uint64_t process_exit_mm(struct process_control_block *pcb);
98 
99 /**
100  * @brief 切换进程
101  *
102  * @param prev 上一个进程的pcb
103  * @param next 将要切换到的进程的pcb
104  * 由于程序在进入内核的时候已经保存了寄存器,因此这里不需要保存寄存器。
105  * 这里切换fs和gs寄存器
106  */
107 #pragma GCC push_options
108 #pragma GCC optimize("O0")
__switch_to(struct process_control_block * prev,struct process_control_block * next)109 void __switch_to(struct process_control_block *prev, struct process_control_block *next)
110 {
111     initial_tss[proc_current_cpu_id].rsp0 = next->thread->rbp;
112     // kdebug("next_rsp = %#018lx   ", next->thread->rsp);
113     //  set_tss64((uint *)phys_2_virt(TSS64_Table), initial_tss[0].rsp0, initial_tss[0].rsp1, initial_tss[0].rsp2,
114     //  initial_tss[0].ist1,
115     //           initial_tss[0].ist2, initial_tss[0].ist3, initial_tss[0].ist4, initial_tss[0].ist5,
116     //           initial_tss[0].ist6, initial_tss[0].ist7);
117 
118     __asm__ __volatile__("movq	%%fs,	%0 \n\t"
119                          : "=a"(prev->thread->fs));
120     __asm__ __volatile__("movq	%%gs,	%0 \n\t"
121                          : "=a"(prev->thread->gs));
122 
123     __asm__ __volatile__("movq	%0,	%%fs \n\t" ::"a"(next->thread->fs));
124     __asm__ __volatile__("movq	%0,	%%gs \n\t" ::"a"(next->thread->gs));
125 }
126 #pragma GCC pop_options
127 
128 /**
129  * @brief 切换进程的fs、gs寄存器
130  * 注意,fs、gs的值在return的时候才会生效,因此本函数不能简化为一个单独的宏
131  * @param fs 目标fs值
132  * @param gs 目标gs值
133  */
process_switch_fsgs(uint64_t fs,uint64_t gs)134 void process_switch_fsgs(uint64_t fs, uint64_t gs)
135 {
136     asm volatile("movq	%0,	%%fs \n\t" ::"a"(fs));
137     asm volatile("movq	%0,	%%gs \n\t" ::"a"(gs));
138 }
139 
140 /**
141  * @brief 打开要执行的程序文件
142  *
143  * @param path
144  * @return int 文件描述符编号
145  */
process_open_exec_file(char * path)146 int process_open_exec_file(char *path)
147 {
148     int fd = enter_syscall_int(SYS_OPEN, (uint64_t)path, O_RDONLY, 0, 0, 0, 0, 0, 0);
149     return fd;
150 }
151 
152 /**
153  * @brief 初始化实时进程rt_pcb
154  *
155  * @return 初始化后的进程
156  *
157  */
process_init_rt_pcb(struct process_control_block * rt_pcb)158 struct process_control_block *process_init_rt_pcb(struct process_control_block *rt_pcb)
159 {
160     // 暂时将实时进程的优先级设置为10
161     rt_pcb->priority = 10;
162     rt_pcb->policy = SCHED_RR;
163     rt_pcb->rt_time_slice = 80;
164     rt_pcb->virtual_runtime = 0x7fffffffffffffff;
165     return rt_pcb;
166 }
167 
168 /**
169  * @brief 内核init进程
170  *
171  * @param arg
172  * @return ul 参数
173  */
174 #pragma GCC push_options
175 #pragma GCC optimize("O0")
initial_kernel_thread(ul arg)176 ul initial_kernel_thread(ul arg)
177 {
178     kinfo("initial proc running...\targ:%#018lx, vruntime=%d", arg, current_pcb->virtual_runtime);
179     int val = 0;
180     val = scm_enable_double_buffer();
181     io_mfence();
182     rs_init_stdio();
183     io_mfence();
184     // block_io_scheduler_init();
185     ahci_init();
186     mount_root_fs();
187     io_mfence();
188     rs_virtio_probe();
189     io_mfence();
190 
191     // 使用单独的内核线程来初始化usb驱动程序
192     // 注释:由于目前usb驱动程序不完善,因此先将其注释掉
193     // int usb_pid = kernel_thread(usb_init, 0, 0);
194 
195     kinfo("LZ4 lib Version=%s", LZ4_versionString());
196     io_mfence();
197     __rust_demo_func();
198     io_mfence();
199 
200     // 准备切换到用户态
201     struct pt_regs *regs;
202 
203     // 若在后面这段代码中触发中断,return时会导致段选择子错误,从而触发#GP,因此这里需要cli
204     cli();
205     current_pcb->thread->rip = (ul)ret_from_intr;
206     current_pcb->thread->rsp = (ul)current_pcb + STACK_SIZE - sizeof(struct pt_regs);
207     current_pcb->thread->fs = USER_DS | 0x3;
208     barrier();
209     current_pcb->thread->gs = USER_DS | 0x3;
210     process_switch_fsgs(current_pcb->thread->fs, current_pcb->thread->gs);
211 
212     // 主动放弃内核线程身份
213     current_pcb->flags &= (~PF_KTHREAD);
214     kdebug("in initial_kernel_thread: flags=%ld", current_pcb->flags);
215 
216     regs = (struct pt_regs *)current_pcb->thread->rsp;
217     // kdebug("current_pcb->thread->rsp=%#018lx", current_pcb->thread->rsp);
218     current_pcb->flags = 0;
219     // 将返回用户层的代码压入堆栈,向rdx传入regs的地址,然后jmp到do_execve这个系统调用api的处理函数
220     // 这里的设计思路和switch_to类似 加载用户态程序:shell.elf
221     __asm__ __volatile__("movq %1, %%rsp   \n\t"
222                          "pushq %2    \n\t"
223                          "jmp rs_exec_init_process  \n\t" ::"D"(current_pcb->thread->rsp),
224                          "m"(current_pcb->thread->rsp), "m"(current_pcb->thread->rip), "c"(NULL),
225                          "d"(NULL)
226                          : "memory");
227 
228     return 1;
229 }
230 #pragma GCC pop_options
231 /**
232  * @brief 当子进程退出后向父进程发送通知
233  *
234  */
process_exit_notify()235 void process_exit_notify()
236 {
237     wait_queue_wakeup(&current_pcb->parent_pcb->wait_child_proc_exit, PROC_INTERRUPTIBLE);
238 }
239 
240 /**
241  * @brief 进程退出时执行的函数
242  *
243  * @param code 返回码
244  * @return ul
245  */
process_do_exit(ul code)246 ul process_do_exit(ul code)
247 {
248     // kinfo("process exiting..., code is %ld.", (long)code);
249     cli();
250     struct process_control_block *pcb = current_pcb;
251 
252     // 进程退出时释放资源
253     process_exit_files(pcb);
254     process_exit_thread(pcb);
255     // todo: 可否在这里释放内存结构体?(在判断共享页引用问题之后)
256 
257     pcb->state = PROC_ZOMBIE;
258     pcb->exit_code = code;
259     sti();
260 
261     process_exit_notify();
262     sched();
263 
264     while (1)
265         pause();
266 }
267 
268 /**
269  * @brief 初始化内核进程
270  *
271  * @param fn 目标程序的地址
272  * @param arg 向目标程序传入的参数
273  * @param flags
274  * @return int
275  */
276 
kernel_thread(int (* fn)(void *),void * arg,unsigned long flags)277 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
278 {
279     struct pt_regs regs;
280     barrier();
281     memset(&regs, 0, sizeof(regs));
282     barrier();
283     // 在rbx寄存器中保存进程的入口地址
284     regs.rbx = (ul)fn;
285     // 在rdx寄存器中保存传入的参数
286     regs.rdx = (ul)arg;
287     barrier();
288     regs.ds = KERNEL_DS;
289     barrier();
290     regs.es = KERNEL_DS;
291     barrier();
292     regs.cs = KERNEL_CS;
293     barrier();
294     regs.ss = KERNEL_DS;
295     barrier();
296 
297     // 置位中断使能标志位
298     regs.rflags = (1 << 9);
299     barrier();
300     // rip寄存器指向内核线程的引导程序
301     regs.rip = (ul)kernel_thread_func;
302     barrier();
303     // kdebug("kernel_thread_func=%#018lx", kernel_thread_func);
304     // kdebug("&kernel_thread_func=%#018lx", &kernel_thread_func);
305     // kdebug("1111\tregs.rip = %#018lx", regs.rip);
306     return do_fork(&regs, flags | CLONE_VM, 0, 0);
307 }
308 
309 /**
310  * @brief 初始化进程模块
311  * ☆前置条件:已完成系统调用模块的初始化
312  */
313 #pragma GCC push_options
314 #pragma GCC optimize("O0")
process_init()315 void process_init()
316 {
317     kinfo("Initializing process...");
318     // rs_test_buddy();
319     io_mfence();
320     rs_process_init();
321     io_mfence();
322 
323     initial_tss[proc_current_cpu_id].rsp0 = initial_thread.rbp;
324 
325     // 初始化pid的写锁
326 
327     spin_init(&process_global_pid_write_lock);
328 
329     // 初始化进程的循环链表
330     list_init(&initial_proc_union.pcb.list);
331     wait_queue_init(&initial_proc_union.pcb.wait_child_proc_exit, NULL);
332 
333     io_mfence();
334     // 初始化init进程的signal相关的信息
335     initial_proc_init_signal(current_pcb);
336     kdebug("Initial process to init files");
337     io_mfence();
338     process_init_files();
339     kdebug("Initial process init files ok");
340     io_mfence();
341 
342     // 临时设置IDLE进程的的虚拟运行时间为0,防止下面的这些内核线程的虚拟运行时间出错
343     current_pcb->virtual_runtime = 0;
344 
345     barrier();
346     kernel_thread(initial_kernel_thread, 10, CLONE_FS | CLONE_SIGNAL); // 初始化内核线程
347     barrier();
348     kthread_mechanism_init(); // 初始化kthread机制
349     barrier();
350 
351     initial_proc_union.pcb.state = PROC_RUNNING;
352     initial_proc_union.pcb.preempt_count = 0;
353     initial_proc_union.pcb.cpu_id = 0;
354     initial_proc_union.pcb.virtual_runtime = (1UL << 60);
355     // 将IDLE进程的虚拟运行时间设置为一个很大的数值
356     current_pcb->virtual_runtime = (1UL << 60);
357 }
358 #pragma GCC pop_options
359 
360 /**
361  * @brief 根据pid获取进程的pcb。存在对应的pcb时,返回对应的pcb的指针,否则返回NULL
362  *  当进程管理模块拥有pcblist_lock之后,调用本函数之前,应当对其加锁
363  * @param pid
364  * @return struct process_control_block*
365  */
process_find_pcb_by_pid(pid_t pid)366 struct process_control_block *process_find_pcb_by_pid(pid_t pid)
367 {
368     // todo: 当进程管理模块拥有pcblist_lock之后,对其加锁
369     struct process_control_block *pcb = initial_proc_union.pcb.next_pcb;
370     // 使用蛮力法搜索指定pid的pcb
371     // todo: 使用哈希表来管理pcb
372     for (; pcb != &initial_proc_union.pcb; pcb = pcb->next_pcb)
373     {
374         if (pcb->pid == pid)
375             return pcb;
376     }
377     return NULL;
378 }
379 
380 /**
381  * @brief 将进程加入到调度器的就绪队列中.
382  *
383  * @param pcb 进程的pcb
384  *
385  * @return true 成功加入调度队列
386  * @return false 进程已经在运行
387  */
process_wakeup(struct process_control_block * pcb)388 int process_wakeup(struct process_control_block *pcb)
389 {
390 
391     BUG_ON(pcb == NULL);
392     if (pcb == NULL)
393         return -EINVAL;
394     // 如果pcb正在调度队列中,则不重复加入调度队列
395     if (pcb->state & PROC_RUNNING)
396         return 0;
397 
398     pcb->state |= PROC_RUNNING;
399     sched_enqueue(pcb, true);
400     return 0;
401 }
402 
403 /**
404  * @brief 将进程加入到调度器的就绪队列中,并标志当前进程需要被调度
405  *
406  * @param pcb 进程的pcb
407  */
process_wakeup_immediately(struct process_control_block * pcb)408 int process_wakeup_immediately(struct process_control_block *pcb)
409 {
410     if (pcb->state & PROC_RUNNING)
411         return 0;
412     int retval = process_wakeup(pcb);
413     if (retval != 0)
414         return retval;
415     // 将当前进程标志为需要调度,缩短新进程被wakeup的时间
416     current_pcb->flags |= PF_NEED_SCHED;
417 
418     if (pcb->cpu_id == current_pcb->cpu_id)
419         sched();
420     else
421         rs_kick_cpu(pcb->cpu_id);
422     return 0;
423 }
424 
425 /**
426  * @brief 释放进程的页表
427  *
428  * @param pcb 要被释放页表的进程
429  * @return uint64_t
430  */
process_exit_mm(struct process_control_block * pcb)431 uint64_t process_exit_mm(struct process_control_block *pcb)
432 {
433     rs_drop_address_space(pcb);
434     return 0;
435 }
436 
437 /**
438  * @brief todo: 回收线程结构体
439  *
440  * @param pcb
441  */
process_exit_thread(struct process_control_block * pcb)442 void process_exit_thread(struct process_control_block *pcb)
443 {
444 }
445 
446 /**
447  * @brief 释放pcb
448  *
449  * @param pcb 要被释放的pcb
450  * @return int
451  */
process_release_pcb(struct process_control_block * pcb)452 int process_release_pcb(struct process_control_block *pcb)
453 {
454     if ((pcb->flags & PF_KTHREAD)) // 释放内核线程的worker private结构体
455         free_kthread_struct(pcb);
456 
457     // 将pcb从pcb链表中移除
458     // todo: 对相关的pcb加锁
459     pcb->prev_pcb->next_pcb = pcb->next_pcb;
460     pcb->next_pcb->prev_pcb = pcb->prev_pcb;
461     process_exit_sighand(pcb);
462     process_exit_signal(pcb);
463     rs_process_exit_fpstate(pcb);
464     rs_procfs_unregister_pid(pcb->pid);
465     // 释放进程的地址空间
466     process_exit_mm(pcb);
467     // 释放当前pcb
468     kfree(pcb);
469     return 0;
470 }
471 
472 /**
473  * @brief 给pcb设置名字
474  *
475  * @param pcb 需要设置名字的pcb
476  * @param pcb_name 保存名字的char数组
477  */
__set_pcb_name(struct process_control_block * pcb,const char * pcb_name)478 static void __set_pcb_name(struct process_control_block *pcb, const char *pcb_name)
479 {
480     // todo:给pcb加锁
481     //  spin_lock(&pcb->alloc_lock);
482     strncpy(pcb->name, pcb_name, PCB_NAME_LEN);
483     // spin_unlock(&pcb->alloc_lock);
484 }
485 
486 /**
487  * @brief 给pcb设置名字
488  *
489  * @param pcb 需要设置名字的pcb
490  * @param pcb_name 保存名字的char数组
491  */
process_set_pcb_name(struct process_control_block * pcb,const char * pcb_name)492 void process_set_pcb_name(struct process_control_block *pcb, const char *pcb_name)
493 {
494     __set_pcb_name(pcb, pcb_name);
495 }
496