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/usb/usb.h>
21 #include <driver/video/video.h>
22 #include <driver/virtio/virtio.h>
23 #include <exception/gate.h>
24 #include <ktest/ktest.h>
25 #include <mm/mmio.h>
26 #include <mm/slab.h>
27 #include <sched/sched.h>
28 #include <syscall/syscall.h>
29 #include <syscall/syscall_num.h>
30 extern int __rust_demo_func();
31 // #pragma GCC push_options
32 // #pragma GCC optimize("O0")
33 
34 spinlock_t process_global_pid_write_lock; // 增加pid的写锁
35 long process_global_pid = 1;              // 系统中最大的pid
36 
37 extern void system_call(void);
38 extern void kernel_thread_func(void);
39 extern void rs_procfs_unregister_pid(uint64_t);
40 
41 ul _stack_start; // initial proc的栈基地址(虚拟地址)
42 extern struct mm_struct initial_mm;
43 extern struct signal_struct INITIAL_SIGNALS;
44 extern struct sighand_struct INITIAL_SIGHAND;
45 
46 extern void process_exit_sighand(struct process_control_block *pcb);
47 extern void process_exit_signal(struct process_control_block *pcb);
48 extern void initial_proc_init_signal(struct process_control_block *pcb);
49 extern void rs_process_exit_fpstate(struct process_control_block *pcb);
50 extern int process_init_files();
51 extern int rs_init_stdio();
52 
53 // 设置初始进程的PCB
54 #define INITIAL_PROC(proc)                                                                                           \
55     {                                                                                                                \
56         .state = PROC_UNINTERRUPTIBLE, .flags = PF_KTHREAD, .preempt_count = 0, .signal = 0, .cpu_id = 0,            \
57         .mm = &initial_mm, .thread = &initial_thread, .addr_limit = 0xffffffffffffffff, .pid = 0, .priority = 2,     \
58         .virtual_runtime = 0, .fds = {0}, .next_pcb = &proc, .prev_pcb = &proc, .parent_pcb = &proc, .exit_code = 0, \
59         .wait_child_proc_exit = 0, .worker_private = NULL, .policy = SCHED_NORMAL, .sig_blocked = 0,                 \
60         .signal = &INITIAL_SIGNALS, .sighand = &INITIAL_SIGHAND,                                                     \
61     }
62 
63 struct thread_struct initial_thread = {
64     .rbp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)),
65     .rsp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)),
66     .fs = KERNEL_DS,
67     .gs = KERNEL_DS,
68     .cr2 = 0,
69     .trap_num = 0,
70     .err_code = 0,
71 };
72 
73 // 初始化 初始进程的union ,并将其链接到.data.init_proc段内
74 union proc_union initial_proc_union
75     __attribute__((__section__(".data.init_proc_union"))) = {INITIAL_PROC(initial_proc_union.pcb)};
76 
77 struct process_control_block *initial_proc[MAX_CPU_NUM] = {&initial_proc_union.pcb, 0};
78 
79 // 为每个核心初始化初始进程的tss
80 struct tss_struct initial_tss[MAX_CPU_NUM] = {[0 ... MAX_CPU_NUM - 1] = INITIAL_TSS};
81 
82 /**
83  * @brief 回收进程的所有文件描述符
84  *
85  * @param pcb 要被回收的进程的pcb
86  * @return uint64_t
87  */
88 extern int process_exit_files(struct process_control_block *pcb);
89 
90 /**
91  * @brief 释放进程的页表
92  *
93  * @param pcb 要被释放页表的进程
94  * @return uint64_t
95  */
96 uint64_t process_exit_mm(struct process_control_block *pcb);
97 
98 /**
99  * @brief 切换进程
100  *
101  * @param prev 上一个进程的pcb
102  * @param next 将要切换到的进程的pcb
103  * 由于程序在进入内核的时候已经保存了寄存器,因此这里不需要保存寄存器。
104  * 这里切换fs和gs寄存器
105  */
106 #pragma GCC push_options
107 #pragma GCC optimize("O0")
__switch_to(struct process_control_block * prev,struct process_control_block * next)108 void __switch_to(struct process_control_block *prev, struct process_control_block *next)
109 {
110     initial_tss[proc_current_cpu_id].rsp0 = next->thread->rbp;
111     // kdebug("next_rsp = %#018lx   ", next->thread->rsp);
112     //  set_tss64((uint *)phys_2_virt(TSS64_Table), initial_tss[0].rsp0, initial_tss[0].rsp1, initial_tss[0].rsp2,
113     //  initial_tss[0].ist1,
114     //           initial_tss[0].ist2, initial_tss[0].ist3, initial_tss[0].ist4, initial_tss[0].ist5,
115     //           initial_tss[0].ist6, initial_tss[0].ist7);
116 
117     __asm__ __volatile__("movq	%%fs,	%0 \n\t"
118                          : "=a"(prev->thread->fs));
119     __asm__ __volatile__("movq	%%gs,	%0 \n\t"
120                          : "=a"(prev->thread->gs));
121 
122     __asm__ __volatile__("movq	%0,	%%fs \n\t" ::"a"(next->thread->fs));
123     __asm__ __volatile__("movq	%0,	%%gs \n\t" ::"a"(next->thread->gs));
124 }
125 #pragma GCC pop_options
126 
127 /**
128  * @brief 切换进程的fs、gs寄存器
129  * 注意,fs、gs的值在return的时候才会生效,因此本函数不能简化为一个单独的宏
130  * @param fs 目标fs值
131  * @param gs 目标gs值
132  */
process_switch_fsgs(uint64_t fs,uint64_t gs)133 void process_switch_fsgs(uint64_t fs, uint64_t gs)
134 {
135     asm volatile("movq	%0,	%%fs \n\t" ::"a"(fs));
136     asm volatile("movq	%0,	%%gs \n\t" ::"a"(gs));
137 }
138 
139 /**
140  * @brief 打开要执行的程序文件
141  *
142  * @param path
143  * @return int 文件描述符编号
144  */
process_open_exec_file(char * path)145 int process_open_exec_file(char *path)
146 {
147     struct pt_regs tmp = {0};
148     tmp.r8 = (uint64_t)path;
149     tmp.r9 = O_RDONLY;
150     int fd = sys_open(&tmp);
151     return fd;
152 }
153 
154 /**
155  * @brief 加载elf格式的程序文件到内存中,并设置regs
156  *
157  * @param regs 寄存器
158  * @param path 文件路径
159  * @return int
160  */
process_load_elf_file(struct pt_regs * regs,char * path)161 static int process_load_elf_file(struct pt_regs *regs, char *path)
162 {
163     int retval = 0;
164     int fd = process_open_exec_file(path);
165 
166     if ((long)fd < 0)
167     {
168         kdebug("(long)fd=%ld", (long)fd);
169         return (unsigned long)fd;
170     }
171 
172     void *buf = kzalloc(PAGE_4K_SIZE, 0);
173     uint64_t pos = 0;
174 
175     struct pt_regs tmp_use_fs = {0};
176     tmp_use_fs.r8 = fd;
177     tmp_use_fs.r9 = 0;
178     tmp_use_fs.r10 = SEEK_SET;
179     retval = sys_lseek(&tmp_use_fs);
180 
181     // 读取 Elf64_Ehdr
182     tmp_use_fs.r8 = fd;
183     tmp_use_fs.r9 = (uint64_t)buf;
184     tmp_use_fs.r10 = sizeof(Elf64_Ehdr);
185     retval = sys_read(&tmp_use_fs);
186 
187     tmp_use_fs.r8 = fd;
188     tmp_use_fs.r9 = 0;
189     tmp_use_fs.r10 = SEEK_CUR;
190     pos = sys_lseek(&tmp_use_fs);
191 
192     if (retval != sizeof(Elf64_Ehdr))
193     {
194         kerror("retval=%d, not equal to sizeof(Elf64_Ehdr):%d", retval, sizeof(Elf64_Ehdr));
195     }
196     retval = 0;
197     if (!elf_check(buf))
198     {
199         kerror("Not an ELF file: %s", path);
200         retval = -ENOTSUP;
201         goto load_elf_failed;
202     }
203 
204 #if ARCH(X86_64)
205     // 暂时只支持64位的文件
206     if (((Elf32_Ehdr *)buf)->e_ident[EI_CLASS] != ELFCLASS64)
207     {
208         kdebug("((Elf32_Ehdr *)buf)->e_ident[EI_CLASS]=%d", ((Elf32_Ehdr *)buf)->e_ident[EI_CLASS]);
209         retval = -EUNSUPPORTED;
210         goto load_elf_failed;
211     }
212     Elf64_Ehdr ehdr = *(Elf64_Ehdr *)buf;
213     // 暂时只支持AMD64架构
214     if (ehdr.e_machine != EM_AMD64)
215     {
216         kerror("e_machine=%d", ehdr.e_machine);
217         retval = -EUNSUPPORTED;
218         goto load_elf_failed;
219     }
220 #else
221 #error Unsupported architecture!
222 #endif
223     if (ehdr.e_type != ET_EXEC)
224     {
225         kerror("Not executable file! filename=%s\tehdr->e_type=%d", path, ehdr.e_type);
226         retval = -EUNSUPPORTED;
227         goto load_elf_failed;
228     }
229     // kdebug("filename=%s:\te_entry=%#018lx", path, ehdr.e_entry);
230     regs->rip = ehdr.e_entry;
231     current_pcb->mm->code_addr_start = ehdr.e_entry;
232 
233     // kdebug("ehdr.e_phoff=%#018lx\t ehdr.e_phentsize=%d, ehdr.e_phnum=%d", ehdr.e_phoff, ehdr.e_phentsize,
234     // ehdr.e_phnum); 将指针移动到program header处
235 
236     // 读取所有的phdr
237     pos = ehdr.e_phoff;
238     tmp_use_fs.r8 = fd;
239     tmp_use_fs.r9 = pos;
240     tmp_use_fs.r10 = SEEK_SET;
241     pos = sys_lseek(&tmp_use_fs);
242 
243     memset(buf, 0, PAGE_4K_SIZE);
244     tmp_use_fs.r8 = fd;
245     tmp_use_fs.r9 = (uint64_t)buf;
246     tmp_use_fs.r10 = (uint64_t)ehdr.e_phentsize * (uint64_t)ehdr.e_phnum;
247     sys_read(&tmp_use_fs);
248 
249     tmp_use_fs.r8 = fd;
250     tmp_use_fs.r9 = 0;
251     tmp_use_fs.r10 = SEEK_CUR;
252     pos = sys_lseek(&tmp_use_fs);
253 
254     if ((long)retval < 0)
255     {
256         kdebug("(unsigned long)filp=%d", (long)retval);
257         retval = -ENOEXEC;
258         goto load_elf_failed;
259     }
260 
261     Elf64_Phdr *phdr = buf;
262     // 将程序加载到内存中
263     for (int i = 0; i < ehdr.e_phnum; ++i, ++phdr)
264     {
265         // kdebug("phdr[%d] phdr->p_offset=%#018lx phdr->p_vaddr=%#018lx phdr->p_memsz=%ld phdr->p_filesz=%ld
266         // phdr->p_type=%d", i, phdr->p_offset, phdr->p_vaddr, phdr->p_memsz, phdr->p_filesz, phdr->p_type);
267 
268         // 不是可加载的段
269         if (phdr->p_type != PT_LOAD)
270             continue;
271 
272         int64_t remain_mem_size = phdr->p_memsz;
273         int64_t remain_file_size = phdr->p_filesz;
274         pos = phdr->p_offset;
275 
276         uint64_t virt_base = 0;
277         uint64_t beginning_offset = 0; // 由于页表映射导致的virtbase与实际的p_vaddr之间的偏移量
278 
279         if (remain_mem_size >= PAGE_2M_SIZE) // 接下来存在映射2M页的情况,因此将vaddr按2M向下对齐
280             virt_base = phdr->p_vaddr & PAGE_2M_MASK;
281         else // 接下来只有4K页的映射
282             virt_base = phdr->p_vaddr & PAGE_4K_MASK;
283 
284         beginning_offset = phdr->p_vaddr - virt_base;
285         remain_mem_size += beginning_offset;
286 
287         while (remain_mem_size > 0)
288         {
289             // kdebug("loading...");
290             int64_t map_size = 0;
291             if (remain_mem_size >= PAGE_2M_SIZE)
292             {
293                 uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
294                 struct vm_area_struct *vma = NULL;
295                 int ret =
296                     mm_create_vma(current_pcb->mm, virt_base, PAGE_2M_SIZE, VM_USER | VM_ACCESS_FLAGS, NULL, &vma);
297 
298                 // 防止内存泄露
299                 if (ret == -EEXIST)
300                     free_pages(Phy_to_2M_Page(pa), 1);
301                 else
302                     mm_map(current_pcb->mm, virt_base, PAGE_2M_SIZE, pa);
303                 // mm_map_vma(vma, pa, 0, PAGE_2M_SIZE);
304                 io_mfence();
305                 memset((void *)virt_base, 0, PAGE_2M_SIZE);
306                 map_size = PAGE_2M_SIZE;
307             }
308             else
309             {
310                 // todo: 使用4K、8K、32K大小内存块混合进行分配,提高空间利用率(减少了bmp的大小)
311                 map_size = ALIGN(remain_mem_size, PAGE_4K_SIZE);
312                 // 循环分配4K大小内存块
313                 for (uint64_t off = 0; off < map_size; off += PAGE_4K_SIZE)
314                 {
315                     uint64_t paddr = virt_2_phys((uint64_t)kmalloc(PAGE_4K_SIZE, 0));
316 
317                     struct vm_area_struct *vma = NULL;
318                     int val = mm_create_vma(current_pcb->mm, virt_base + off, PAGE_4K_SIZE, VM_USER | VM_ACCESS_FLAGS,
319                                             NULL, &vma);
320                     // kdebug("virt_base=%#018lx", virt_base + off);
321                     if (val == -EEXIST)
322                         kfree(phys_2_virt(paddr));
323                     else
324                         mm_map(current_pcb->mm, virt_base + off, PAGE_4K_SIZE, paddr);
325                     // mm_map_vma(vma, paddr, 0, PAGE_4K_SIZE);
326                     io_mfence();
327                     memset((void *)(virt_base + off), 0, PAGE_4K_SIZE);
328                 }
329             }
330 
331             tmp_use_fs.r8 = fd;
332             tmp_use_fs.r9 = pos;
333             tmp_use_fs.r10 = SEEK_SET;
334             pos = sys_lseek(&tmp_use_fs);
335 
336             int64_t val = 0;
337             if (remain_file_size > 0)
338             {
339                 int64_t to_trans = (remain_file_size > PAGE_2M_SIZE) ? PAGE_2M_SIZE : remain_file_size;
340 
341                 void *buf3 = kzalloc(PAGE_4K_SIZE, 0);
342                 while (to_trans > 0)
343                 {
344                     int64_t x = 0;
345                     tmp_use_fs.r8 = fd;
346                     tmp_use_fs.r9 = (uint64_t)buf3;
347                     tmp_use_fs.r10 = to_trans;
348                     x = sys_read(&tmp_use_fs);
349                     memcpy(virt_base + beginning_offset + val, buf3, x);
350                     val += x;
351                     to_trans -= x;
352                     tmp_use_fs.r8 = fd;
353                     tmp_use_fs.r9 = 0;
354                     tmp_use_fs.r10 = SEEK_CUR;
355                     pos = sys_lseek(&tmp_use_fs);
356                 }
357                 kfree(buf3);
358 
359                 // kdebug("virt_base + beginning_offset=%#018lx, val=%d, to_trans=%d", virt_base + beginning_offset,
360                 // val,
361                 //        to_trans);
362                 // kdebug("to_trans=%d", to_trans);
363             }
364 
365             if (val < 0)
366                 goto load_elf_failed;
367 
368             remain_mem_size -= map_size;
369             remain_file_size -= val;
370             virt_base += map_size;
371         }
372     }
373 
374     // 分配2MB的栈内存空间
375     regs->rsp = current_pcb->mm->stack_start;
376     regs->rbp = current_pcb->mm->stack_start;
377 
378     {
379         struct vm_area_struct *vma = NULL;
380         uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
381         int val = mm_create_vma(current_pcb->mm, current_pcb->mm->stack_start - PAGE_2M_SIZE, PAGE_2M_SIZE,
382                                 VM_USER | VM_ACCESS_FLAGS, NULL, &vma);
383         if (val == -EEXIST)
384             free_pages(Phy_to_2M_Page(pa), 1);
385         else
386             mm_map_vma(vma, pa, 0, PAGE_2M_SIZE);
387     }
388 
389     // 清空栈空间
390     memset((void *)(current_pcb->mm->stack_start - PAGE_2M_SIZE), 0, PAGE_2M_SIZE);
391 
392 load_elf_failed:;
393     {
394         struct pt_regs tmp = {0};
395         tmp.r8 = fd;
396         sys_close(&tmp);
397     }
398 
399     if (buf != NULL)
400         kfree(buf);
401     return retval;
402 }
403 /**
404  * @brief 使当前进程去执行新的代码
405  *
406  * @param regs 当前进程的寄存器
407  * @param path 可执行程序的路径
408  * @param argv 参数列表
409  * @param envp 环境变量
410  * @return ul 错误码
411  */
412 #pragma GCC push_options
413 #pragma GCC optimize("O0")
do_execve(struct pt_regs * regs,char * path,char * argv[],char * envp[])414 ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[])
415 {
416 
417     // 当前进程正在与父进程共享地址空间,需要创建
418     // 独立的地址空间才能使新程序正常运行
419     if (current_pcb->flags & PF_VFORK)
420     {
421         // kdebug("proc:%d  creating new mem space", current_pcb->pid);
422         // 分配新的内存空间分布结构体
423         struct mm_struct *new_mms = (struct mm_struct *)kmalloc(sizeof(struct mm_struct), 0);
424         memset(new_mms, 0, sizeof(struct mm_struct));
425         current_pcb->mm = new_mms;
426 
427         // 分配顶层页表, 并设置顶层页表的物理地址
428         new_mms->pgd = (pml4t_t *)virt_2_phys(kmalloc(PAGE_4K_SIZE, 0));
429 
430         // 由于高2K部分为内核空间,在接下来需要覆盖其数据,因此不用清零
431         memset(phys_2_virt(new_mms->pgd), 0, PAGE_4K_SIZE / 2);
432 
433         // 拷贝内核空间的页表指针
434         memcpy(phys_2_virt(new_mms->pgd) + 256, phys_2_virt(initial_proc[proc_current_cpu_id]) + 256, PAGE_4K_SIZE / 2);
435     }
436 
437     // 设置用户栈和用户堆的基地址
438     unsigned long stack_start_addr = 0x6ffff0a00000UL;
439     const uint64_t brk_start_addr = 0x700000000000UL;
440 
441     process_switch_mm(current_pcb);
442 
443     // 为用户态程序设置地址边界
444     if (!(current_pcb->flags & PF_KTHREAD))
445         current_pcb->addr_limit = USER_MAX_LINEAR_ADDR;
446 
447     current_pcb->mm->code_addr_end = 0;
448     current_pcb->mm->data_addr_start = 0;
449     current_pcb->mm->data_addr_end = 0;
450     current_pcb->mm->rodata_addr_start = 0;
451     current_pcb->mm->rodata_addr_end = 0;
452     current_pcb->mm->bss_start = 0;
453     current_pcb->mm->bss_end = 0;
454     current_pcb->mm->brk_start = brk_start_addr;
455     current_pcb->mm->brk_end = brk_start_addr;
456     current_pcb->mm->stack_start = stack_start_addr;
457 
458     // 清除进程的vfork标志位
459     current_pcb->flags &= ~PF_VFORK;
460 
461     // 加载elf格式的可执行文件
462     int tmp = process_load_elf_file(regs, path);
463     if (tmp < 0)
464         goto exec_failed;
465 
466     int argc = 0;
467     char **dst_argv = NULL;
468     // kdebug("stack_start_addr=%#018lx", stack_start_addr);
469     // 拷贝参数列表
470     if (argv != NULL)
471     {
472 
473         // 目标程序的argv基地址指针,最大8个参数
474         dst_argv = (char **)(stack_start_addr - (sizeof(char **) << 3));
475         uint64_t str_addr = (uint64_t)dst_argv;
476 
477         for (argc = 0; argc < 8 && argv[argc] != NULL; ++argc)
478         {
479 
480             if (*argv[argc] == NULL)
481                 break;
482 
483             // 测量参数的长度(最大1023)
484             int argv_len = strnlen_user(argv[argc], 1023) + 1;
485             strncpy((char *)(str_addr - argv_len), argv[argc], argv_len - 1);
486             str_addr -= argv_len;
487             dst_argv[argc] = (char *)str_addr;
488             // 字符串加上结尾字符
489             ((char *)str_addr)[argv_len] = '\0';
490         }
491 
492         // 重新设定栈基址,并预留空间防止越界
493 
494         stack_start_addr = str_addr - 8;
495     }
496 
497     // kdebug("stack_start_addr=%#018lx", stack_start_addr);
498     // ==== 生成relibc所需的Stack结构体
499     {
500         uint64_t *ptr_stack = (uint64_t *)(stack_start_addr - 8);
501         if (argc == 0)
502             *ptr_stack = 0;
503         else
504             *ptr_stack = (uint64_t)dst_argv;
505         ptr_stack--;
506         *ptr_stack = argc;
507         stack_start_addr -= 16;
508     }
509 
510     // 传递参数(旧版libc)
511     regs->rdi = argc;
512     regs->rsi = (uint64_t)dst_argv;
513     // 设置用户栈基地址
514     current_pcb->mm->stack_start = stack_start_addr;
515     regs->rsp = regs->rbp = stack_start_addr;
516     // kdebug("execve ok");
517     // 设置进程的段选择子为用户态可访问
518     regs->cs = USER_CS | 3;
519     regs->ds = USER_DS | 3;
520     regs->ss = USER_DS | 0x3;
521     regs->rflags = 0x200246;
522     regs->rax = 1;
523     regs->es = 0;
524 
525     return 0;
526 
527 exec_failed:;
528     process_do_exit(tmp);
529 }
530 #pragma GCC pop_options
531 
532 /**
533  * @brief 初始化实时进程rt_pcb
534  *
535  * @return 初始化后的进程
536  *
537  */
process_init_rt_pcb(struct process_control_block * rt_pcb)538 struct process_control_block *process_init_rt_pcb(struct process_control_block *rt_pcb)
539 {
540     // 暂时将实时进程的优先级设置为10
541     rt_pcb->priority = 10;
542     rt_pcb->policy = SCHED_RR;
543     rt_pcb->rt_time_slice = 80;
544     rt_pcb->virtual_runtime = 0x7fffffffffffffff;
545     return rt_pcb;
546 }
547 
548 /**
549  * @brief 内核init进程
550  *
551  * @param arg
552  * @return ul 参数
553  */
554 #pragma GCC push_options
555 #pragma GCC optimize("O0")
initial_kernel_thread(ul arg)556 ul initial_kernel_thread(ul arg)
557 {
558     kinfo("initial proc running...\targ:%#018lx, vruntime=%d", arg, current_pcb->virtual_runtime);
559     int val = 0;
560     val = scm_enable_double_buffer();
561 
562     rs_init_stdio();
563     // block_io_scheduler_init();
564     ahci_init();
565     mount_root_fs();
566     rs_virtio_probe();
567     // 使用单独的内核线程来初始化usb驱动程序
568     // 注释:由于目前usb驱动程序不完善,因此先将其注释掉
569     // int usb_pid = kernel_thread(usb_init, 0, 0);
570 
571     kinfo("LZ4 lib Version=%s", LZ4_versionString());
572     __rust_demo_func();
573     // while (1)
574     // {
575     //     /* code */
576     // }
577 
578     // 对completion完成量进行测试
579     // __test_completion();
580 
581     // // 对一些组件进行单元测试
582     uint64_t tpid[] = {
583         // ktest_start(ktest_test_bitree, 0), ktest_start(ktest_test_kfifo, 0), ktest_start(ktest_test_mutex, 0),
584         // ktest_start(ktest_test_idr, 0),
585         // usb_pid,
586     };
587 
588     // kinfo("Waiting test thread exit...");
589     // // 等待测试进程退出
590     // for (int i = 0; i < sizeof(tpid) / sizeof(uint64_t); ++i)
591     //     waitpid(tpid[i], NULL, NULL);
592     // kinfo("All test done.");
593 
594     // 测试实时进程
595 
596     // struct process_control_block *test_rt1 = kthread_run_rt(&test, NULL, "test rt");
597     // kdebug("process:rt test kthread is created!!!!");
598 
599     // 准备切换到用户态
600     struct pt_regs *regs;
601 
602     // 若在后面这段代码中触发中断,return时会导致段选择子错误,从而触发#GP,因此这里需要cli
603     cli();
604     current_pcb->thread->rip = (ul)ret_from_intr;
605     current_pcb->thread->rsp = (ul)current_pcb + STACK_SIZE - sizeof(struct pt_regs);
606     current_pcb->thread->fs = USER_DS | 0x3;
607     barrier();
608     current_pcb->thread->gs = USER_DS | 0x3;
609     process_switch_fsgs(current_pcb->thread->fs, current_pcb->thread->gs);
610 
611     // 主动放弃内核线程身份
612     current_pcb->flags &= (~PF_KTHREAD);
613     kdebug("in initial_kernel_thread: flags=%ld", current_pcb->flags);
614 
615     regs = (struct pt_regs *)current_pcb->thread->rsp;
616     // kdebug("current_pcb->thread->rsp=%#018lx", current_pcb->thread->rsp);
617     current_pcb->flags = 0;
618     // 将返回用户层的代码压入堆栈,向rdx传入regs的地址,然后jmp到do_execve这个系统调用api的处理函数
619     // 这里的设计思路和switch_to类似 加载用户态程序:shell.elf
620     __asm__ __volatile__("movq %1, %%rsp   \n\t"
621                          "pushq %2    \n\t"
622                          "jmp do_execve  \n\t" ::"D"(current_pcb->thread->rsp),
623                          "m"(current_pcb->thread->rsp), "m"(current_pcb->thread->rip), "S"("/bin/shell.elf"), "c"(NULL),
624                          "d"(NULL)
625                          : "memory");
626 
627     return 1;
628 }
629 #pragma GCC pop_options
630 /**
631  * @brief 当子进程退出后向父进程发送通知
632  *
633  */
process_exit_notify()634 void process_exit_notify()
635 {
636     wait_queue_wakeup(&current_pcb->parent_pcb->wait_child_proc_exit, PROC_INTERRUPTIBLE);
637 }
638 
639 /**
640  * @brief 进程退出时执行的函数
641  *
642  * @param code 返回码
643  * @return ul
644  */
process_do_exit(ul code)645 ul process_do_exit(ul code)
646 {
647     // kinfo("process exiting..., code is %ld.", (long)code);
648     cli();
649     struct process_control_block *pcb = current_pcb;
650 
651     // 进程退出时释放资源
652     process_exit_files(pcb);
653     process_exit_thread(pcb);
654     // todo: 可否在这里释放内存结构体?(在判断共享页引用问题之后)
655 
656     pcb->state = PROC_ZOMBIE;
657     pcb->exit_code = code;
658     sti();
659 
660     process_exit_notify();
661     sched();
662 
663     while (1)
664         pause();
665 }
666 
667 /**
668  * @brief 初始化内核进程
669  *
670  * @param fn 目标程序的地址
671  * @param arg 向目标程序传入的参数
672  * @param flags
673  * @return int
674  */
675 
kernel_thread(int (* fn)(void *),void * arg,unsigned long flags)676 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
677 {
678     struct pt_regs regs;
679     barrier();
680     memset(&regs, 0, sizeof(regs));
681     barrier();
682     // 在rbx寄存器中保存进程的入口地址
683     regs.rbx = (ul)fn;
684     // 在rdx寄存器中保存传入的参数
685     regs.rdx = (ul)arg;
686     barrier();
687     regs.ds = KERNEL_DS;
688     barrier();
689     regs.es = KERNEL_DS;
690     barrier();
691     regs.cs = KERNEL_CS;
692     barrier();
693     regs.ss = KERNEL_DS;
694     barrier();
695 
696     // 置位中断使能标志位
697     regs.rflags = (1 << 9);
698     barrier();
699     // rip寄存器指向内核线程的引导程序
700     regs.rip = (ul)kernel_thread_func;
701     barrier();
702     // kdebug("kernel_thread_func=%#018lx", kernel_thread_func);
703     // kdebug("&kernel_thread_func=%#018lx", &kernel_thread_func);
704     // kdebug("1111\tregs.rip = %#018lx", regs.rip);
705     return do_fork(&regs, flags | CLONE_VM, 0, 0);
706 }
707 
708 /**
709  * @brief 初始化进程模块
710  * ☆前置条件:已完成系统调用模块的初始化
711  */
process_init()712 void process_init()
713 {
714     kinfo("Initializing process...");
715 
716     initial_tss[proc_current_cpu_id].rsp0 = initial_thread.rbp;
717 
718     // 初始化pid的写锁
719 
720     spin_init(&process_global_pid_write_lock);
721 
722     // 初始化进程的循环链表
723     list_init(&initial_proc_union.pcb.list);
724     wait_queue_init(&initial_proc_union.pcb.wait_child_proc_exit, NULL);
725 
726     // 初始化init进程的signal相关的信息
727     initial_proc_init_signal(current_pcb);
728     kdebug("Initial process to init files");
729     process_init_files();
730     kdebug("Initial process init files ok");
731 
732     // 临时设置IDLE进程的的虚拟运行时间为0,防止下面的这些内核线程的虚拟运行时间出错
733     current_pcb->virtual_runtime = 0;
734     barrier();
735     kernel_thread(initial_kernel_thread, 10, CLONE_FS | CLONE_SIGNAL); // 初始化内核线程
736     barrier();
737     kthread_mechanism_init(); // 初始化kthread机制
738 
739     initial_proc_union.pcb.state = PROC_RUNNING;
740     initial_proc_union.pcb.preempt_count = 0;
741     initial_proc_union.pcb.cpu_id = 0;
742     initial_proc_union.pcb.virtual_runtime = (1UL << 60);
743     // 将IDLE进程的虚拟运行时间设置为一个很大的数值
744     current_pcb->virtual_runtime = (1UL << 60);
745 }
746 
747 /**
748  * @brief 根据pid获取进程的pcb。存在对应的pcb时,返回对应的pcb的指针,否则返回NULL
749  *  当进程管理模块拥有pcblist_lock之后,调用本函数之前,应当对其加锁
750  * @param pid
751  * @return struct process_control_block*
752  */
process_find_pcb_by_pid(pid_t pid)753 struct process_control_block *process_find_pcb_by_pid(pid_t pid)
754 {
755     // todo: 当进程管理模块拥有pcblist_lock之后,对其加锁
756     struct process_control_block *pcb = initial_proc_union.pcb.next_pcb;
757     // 使用蛮力法搜索指定pid的pcb
758     // todo: 使用哈希表来管理pcb
759     for (; pcb != &initial_proc_union.pcb; pcb = pcb->next_pcb)
760     {
761         if (pcb->pid == pid)
762             return pcb;
763     }
764     return NULL;
765 }
766 
767 /**
768  * @brief 将进程加入到调度器的就绪队列中.
769  *
770  * @param pcb 进程的pcb
771  *
772  * @return true 成功加入调度队列
773  * @return false 进程已经在运行
774  */
process_wakeup(struct process_control_block * pcb)775 int process_wakeup(struct process_control_block *pcb)
776 {
777 
778     BUG_ON(pcb == NULL);
779     if (pcb == NULL)
780         return -EINVAL;
781     // 如果pcb正在调度队列中,则不重复加入调度队列
782     if (pcb->state & PROC_RUNNING)
783         return 0;
784 
785     pcb->state |= PROC_RUNNING;
786     sched_enqueue(pcb, true);
787     return 0;
788 }
789 
790 /**
791  * @brief 将进程加入到调度器的就绪队列中,并标志当前进程需要被调度
792  *
793  * @param pcb 进程的pcb
794  */
process_wakeup_immediately(struct process_control_block * pcb)795 int process_wakeup_immediately(struct process_control_block *pcb)
796 {
797     if (pcb->state & PROC_RUNNING)
798         return 0;
799     int retval = process_wakeup(pcb);
800     if (retval != 0)
801         return retval;
802     // 将当前进程标志为需要调度,缩短新进程被wakeup的时间
803     current_pcb->flags |= PF_NEED_SCHED;
804 
805     if (pcb->cpu_id == current_pcb->cpu_id)
806         sched();
807     else
808         kick_cpu(pcb->cpu_id);
809     return 0;
810 }
811 
812 /**
813  * @brief 释放进程的页表
814  *
815  * @param pcb 要被释放页表的进程
816  * @return uint64_t
817  */
process_exit_mm(struct process_control_block * pcb)818 uint64_t process_exit_mm(struct process_control_block *pcb)
819 {
820     if (pcb->flags & CLONE_VM)
821         return 0;
822     if (pcb->mm == NULL)
823     {
824         kdebug("pcb->mm==NULL");
825         return 0;
826     }
827     if (pcb->mm->pgd == NULL)
828     {
829         kdebug("pcb->mm->pgd==NULL");
830         return 0;
831     }
832 
833     // // 获取顶层页表
834     pml4t_t *current_pgd = (pml4t_t *)phys_2_virt(pcb->mm->pgd);
835 
836     // 循环释放VMA中的内存
837     struct vm_area_struct *vma = pcb->mm->vmas;
838     while (vma != NULL)
839     {
840 
841         struct vm_area_struct *cur_vma = vma;
842         vma = cur_vma->vm_next;
843 
844         uint64_t pa;
845         mm_unmap_vma(pcb->mm, cur_vma, &pa);
846 
847         uint64_t size = (cur_vma->vm_end - cur_vma->vm_start);
848 
849         // 释放内存
850         switch (size)
851         {
852         case PAGE_4K_SIZE:
853             kfree(phys_2_virt(pa));
854             break;
855         default:
856             break;
857         }
858         vm_area_del(cur_vma);
859         vm_area_free(cur_vma);
860     }
861 
862     // 释放顶层页表
863     kfree(current_pgd);
864     if (unlikely(pcb->mm->vmas != NULL))
865     {
866         kwarn("pcb.mm.vmas!=NULL");
867     }
868     // 释放内存空间分布结构体
869     kfree(pcb->mm);
870 
871     return 0;
872 }
873 
874 /**
875  * @brief todo: 回收线程结构体
876  *
877  * @param pcb
878  */
process_exit_thread(struct process_control_block * pcb)879 void process_exit_thread(struct process_control_block *pcb)
880 {
881 }
882 
883 /**
884  * @brief 释放pcb
885  *
886  * @param pcb 要被释放的pcb
887  * @return int
888  */
process_release_pcb(struct process_control_block * pcb)889 int process_release_pcb(struct process_control_block *pcb)
890 {
891     // 释放子进程的页表
892     process_exit_mm(pcb);
893     if ((pcb->flags & PF_KTHREAD)) // 释放内核线程的worker private结构体
894         free_kthread_struct(pcb);
895 
896     // 将pcb从pcb链表中移除
897     // todo: 对相关的pcb加锁
898     pcb->prev_pcb->next_pcb = pcb->next_pcb;
899     pcb->next_pcb->prev_pcb = pcb->prev_pcb;
900     process_exit_sighand(pcb);
901     process_exit_signal(pcb);
902     rs_process_exit_fpstate(pcb);
903     rs_procfs_unregister_pid(pcb->pid);
904     // 释放当前pcb
905     kfree(pcb);
906     return 0;
907 }
908 
909 /**
910  * @brief 给pcb设置名字
911  *
912  * @param pcb 需要设置名字的pcb
913  * @param pcb_name 保存名字的char数组
914  */
__set_pcb_name(struct process_control_block * pcb,const char * pcb_name)915 static void __set_pcb_name(struct process_control_block *pcb, const char *pcb_name)
916 {
917     // todo:给pcb加锁
918     //  spin_lock(&pcb->alloc_lock);
919     strncpy(pcb->name, pcb_name, PCB_NAME_LEN);
920     // spin_unlock(&pcb->alloc_lock);
921 }
922 
923 /**
924  * @brief 给pcb设置名字
925  *
926  * @param pcb 需要设置名字的pcb
927  * @param pcb_name 保存名字的char数组
928  */
process_set_pcb_name(struct process_control_block * pcb,const char * pcb_name)929 void process_set_pcb_name(struct process_control_block *pcb, const char *pcb_name)
930 {
931     __set_pcb_name(pcb, pcb_name);
932 }
933