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