+ llist_delete(&proc->grp_member);
+ llist_append(&gruppenfuhrer->grp_member, &proc->grp_member);
+
+ proc->pgid = pgid;
+ return 0;
+}
+
+void
+init_proc_user_space(struct proc_info* pcb)
+{
+ vmm_mount_pd(PD_MOUNT_1, pcb->page_table);
+
+ /*--- 分配用户栈 ---*/
+
+ // 注册用户栈区域
+ region_add(
+ &pcb->mm.regions, USTACK_END, USTACK_TOP, REGION_RW | REGION_RSHARED);
+
+ // 预留地址空间,具体物理页将由Page Fault Handler按需分配。
+ for (uintptr_t i = PG_ALIGN(USTACK_END); i < USTACK_TOP; i += PG_SIZE) {
+ vmm_set_mapping(PD_MOUNT_1, i, 0, PG_ALLOW_USER | PG_WRITE, VMAP_NULL);
+ }
+
+ // todo: other uspace initialization stuff
+
+ vmm_unmount_pd(PD_MOUNT_1);
+}
+
+void
+__mark_region(uintptr_t start_vpn, uintptr_t end_vpn, int attr)
+{
+ for (size_t i = start_vpn; i <= end_vpn; i++) {
+ x86_pte_t* curproc = &PTE_MOUNTED(PD_REFERENCED, i);
+ x86_pte_t* newproc = &PTE_MOUNTED(PD_MOUNT_1, i);
+ cpu_invplg(newproc);
+
+ if ((attr & REGION_MODE_MASK) == REGION_RSHARED) {
+ // 如果读共享,则将两者的都标注为只读,那么任何写入都将会应用COW策略。
+ cpu_invplg(curproc);
+ cpu_invplg(i << 12);
+ *curproc = *curproc & ~PG_WRITE;
+ *newproc = *newproc & ~PG_WRITE;
+ } else {
+ // 如果是私有页,则将该页从新进程中移除。
+ *newproc = 0;
+ }
+ }
+}
+
+pid_t
+dup_proc()
+{
+ struct proc_info* pcb = alloc_process();
+ pcb->mm.u_heap = __current->mm.u_heap;
+ pcb->intr_ctx = __current->intr_ctx;
+ pcb->parent = __current;
+
+ memcpy(pcb->fdtable, __current->fdtable, sizeof(struct v_fdtable));
+ region_copy(&__current->mm.regions, &pcb->mm.regions);
+
+ setup_proc_mem(pcb, PD_REFERENCED);
+
+ // 根据 mm_region 进一步配置页表
+
+ struct mm_region *pos, *n;
+ llist_for_each(pos, n, &pcb->mm.regions.head, head)
+ {
+ // 如果写共享,则不作处理。
+ if ((pos->attr & REGION_WSHARED)) {
+ continue;
+ }
+
+ uintptr_t start_vpn = pos->start >> 12;
+ uintptr_t end_vpn = pos->end >> 12;
+ __mark_region(start_vpn, end_vpn, pos->attr);
+ }
+
+ vmm_unmount_pd(PD_MOUNT_1);