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(¤t_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(®s, 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(®s, 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