Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/kernel/syscalls/fork.c 3 * 4 * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/asm.h> 9 #include <fiwix/kernel.h> 10 #include <fiwix/types.h> 11 #include <fiwix/segments.h> 12 #include <fiwix/sigcontext.h> 13 #include <fiwix/process.h> 14 #include <fiwix/sched.h> 15 #include <fiwix/sleep.h> 16 #include <fiwix/mm.h> 17 #include <fiwix/errno.h> 18 #include <fiwix/stdio.h> 19 #include <fiwix/string.h> 20 21 int sys_fork(int arg1, int arg2, int arg3, int arg4, int arg5, struct sigcontext *sc) 22 { 23 int count, pages; 24 unsigned int n; 25 unsigned int *child_pgdir; 26 struct sigcontext *stack; 27 struct proc *child, *p; 28 struct vma *vma; 29 __pid_t pid; 30 31 #ifdef __DEBUG__ 32 printk("(pid %d) sys_fork()\n", current->pid); 33 #endif /*__DEBUG__ */ 34 35 /* check the number of processes already allocated by this UID */ 36 count = 0; 37 FOR_EACH_PROCESS(p) { 38 if(p->uid == current->uid) { 39 count++; 40 } 41 p = p->next; 42 } 43 if(count > current->rlim[RLIMIT_NPROC].rlim_cur) { 44 printk("WARNING: %s(): RLIMIT_NPROC exceeded.\n", __FUNCTION__); 45 return -EAGAIN; 46 } 47 48 if(!(pid = get_unused_pid())) { 49 return -EAGAIN; 50 } 51 if(!(child = get_proc_free())) { 52 return -EAGAIN; 53 } 54 55 /* 56 * This memcpy() will overwrite the prev and next pointers, so that's 57 * the reason why proc_slot_init() is separated from get_proc_free(). 58 */ 59 memcpy_b(child, current, sizeof(struct proc)); 60 61 proc_slot_init(child); 62 child->pid = pid; 63 memset_b(&child->tss, NULL, sizeof(struct i386tss)); 64 sprintk(child->pidstr, "%d", child->pid); 65 66 if(!(child_pgdir = (void *)kmalloc())) { 67 release_proc(child); 68 return -ENOMEM; 69 } 70 child->rss++; 71 memcpy_b(child_pgdir, kpage_dir, PAGE_SIZE); 72 child->tss.cr3 = V2P((unsigned int)child_pgdir); 73 74 child->ppid = current->pid; 75 child->flags = 0; 76 child->children = 0; 77 child->cpu_count = child->priority; 78 child->start_time = CURRENT_TICKS; 79 child->sleep_address = NULL; 80 81 memcpy_b(child->vma, current->vma, sizeof(child->vma)); 82 vma = child->vma; 83 for(n = 0; n < VMA_REGIONS && vma->start; n++, vma++) { 84 if(vma->inode) { 85 vma->inode->count++; 86 } 87 } 88 89 child->sigpending = 0; 90 child->sigexecuting = 0; 91 memset_b(&child->sc, NULL, sizeof(struct sigcontext)); 92 memset_b(&child->usage, NULL, sizeof(struct rusage)); 93 memset_b(&child->cusage, NULL, sizeof(struct rusage)); 94 child->it_real_interval = 0; 95 child->it_real_value = 0; 96 child->it_virt_interval = 0; 97 child->it_virt_value = 0; 98 child->it_prof_interval = 0; 99 child->it_prof_value = 0; 100 101 if(!(child->tss.esp0 = kmalloc())) { 102 kfree((unsigned int)child_pgdir); 103 kfree((unsigned int)child->vma); 104 release_proc(child); 105 return -ENOMEM; 106 } 107 108 if(!(pages = clone_pages(child))) { 109 printk("WARNING: %s(): not enough memory, can't clone pages.\n", __FUNCTION__); 110 free_page_tables(child); 111 kfree((unsigned int)child_pgdir); 112 kfree((unsigned int)child->vma); 113 release_proc(child); 114 return -ENOMEM; 115 } 116 child->rss += pages; 117 invalidate_tlb(); 118 119 child->tss.esp0 += PAGE_SIZE - 4; 120 child->rss++; 121 child->tss.ss0 = KERNEL_DS; 122 123 memcpy_b((unsigned int *)(child->tss.esp0 & PAGE_MASK), (void *)((unsigned int)(sc) & PAGE_MASK), PAGE_SIZE); 124 stack = (struct sigcontext *)((child->tss.esp0 & PAGE_MASK) + ((unsigned int)(sc) & ~PAGE_MASK)); 125 126 child->tss.eip = (unsigned int)return_from_syscall; 127 child->tss.esp = (unsigned int)stack; 128 stack->eax = 0; /* child returns 0 */ 129 130 /* increase file descriptors usage */ 131 for(n = 0; n < OPEN_MAX; n++) { 132 if(current->fd[n]) { 133 fd_table[current->fd[n]].count++; 134 } 135 } 136 if(current->root) { 137 current->root->count++; 138 } 139 if(current->pwd) { 140 current->pwd->count++; 141 } 142 143 kstat.processes++; 144 nr_processes++; 145 current->children++; 146 runnable(child); 147 148 return child->pid; /* parent returns child's PID */ 149 }