diff --git a/content/posts/2022-11-19-Linux-Kernel-sys_fork.md b/content/posts/2022-11-19-Linux-Kernel-sys_fork.md new file mode 100644 index 0000000..9fb3fa5 --- /dev/null +++ b/content/posts/2022-11-19-Linux-Kernel-sys_fork.md @@ -0,0 +1,140 @@ +--- +title: Linux Kernel, syscalls +date: 2022-11-19T +slug: linux-kernel-sys-fork +description: "" +--- + +#### sys_fork() + +```asm +.align 2 +_sys_fork: + call _find_empty_process + testl %eax,%eax + js 1f + push %gs + pushl %esi + pushl %edi + pushl %ebp + pushl %eax + call _copy_process + addl $20,%esp +1: ret +``` + +##### `FUNCTION find_empty_process()` + +```assembly +A: + IF ++last_pid < 0 + last_pid = 1 + FOR i : 0 -> NR_TASKS + IF task[i] && task[i].pid == last_pid + GOTO A + FOR i : 1 -> NR_TASKS + IF NOT task[i] + RETURN i + RETURN -1 +``` + + + +1. Set last_pid to 1 or more. + +2. From taskid from 0 to max_tasks, if task exists and pid is last_pid then increases pid and again. +3. From taskid from 1 to max_tasks, if tasks not exists, return. + +-> It just iterates through tasks and find last taskid linearly. + + + +##### `FUNCTION copy_process` + +`<- nr, EBP, EDI, ESI, GS, EBX~EDX, CS~FS, EIP, EFLAGS, ESP, SS` +`-> INT` + + +```assembly +TASK_STRUCT P +INT I +FILE F + +P = (TASK_STRUCT)(GET_FREE_PAGE()) + +IF NOT P + RET ERR + +SET P + START_TIME = RUNNING + PID = LAST_PID + FATHER = CURRENT_PID + COUNTER = PRIORITY + START_TIME = jiffies + SIGNAL, ALARM, LEADER, UTIME, STIME, CUTIME, CSDTIME, BACK_LINK = 0 + + SET TSS + BACK_LINK = 0 + ESP0 = PAGE_SIZE + ADDR(P) + SS0 = 0x10 + EAX = 0 + ES ~ GS = 0xFFFF + LDT = _LDT(nr) + + EIP, EFLAGS = ARGUMENT + ECX ~ EDI = ARGUMENT + + TRACR_BITMAP = 0x80000000 + +COPY_MEM (nr, p) +IF <- + FREE_PAGE ADDR(P) + RET ERR + +FOR i : 0 ~ NR_OPEN + IF + f = P.filp[i] + THEN + INCR f.f_count 1 + +IF + CURRENT.PWD +THEN + INCR CURRENT.PWD.i_count 1 + +IF + CURRENT.ROOT +THEN + INCR CURRENT.ROOT.i_count 1 + +SET_TSS_DESC <- (GDT + nr/2 + FIRST_TSS_ENTRY) , P.TSS +SET_LDT_DESC <- (GDT + nr/2 + FIRST_LDT_ENTRY) , P.LDT + +task(nr) <- p + +RET last_pid +``` + + + +"nr" passed is the index of the new task in the task array, where each element corresponds to a process slot. + +fork() copies the parent's kernel context, as well as general registers and segment selectors required for a new process to run in user space. + +It creates a new task structure from a new free page and sets up default values and certain parameters inherited from the parent, such as process ID, priority, and execution times. + +Then it copies memory regions from the parent to the new process, referred to by "nr," which is the index of the new process in the task array. + +Changes the parent process's working directory (PWD) and root directory reference counters, incrementing them by 1 to reflect the new child process now also using these resources. + +Sets the Task State Segment (TSS) and Local Descriptor Table (LDT) entries, which are x86-specific structures used for task switching and memory segmentation, respectively. + +TSS holds information about the task's stack for privilege level changes and also the hardware context when a task switch occurs. + +LDT is a segment descriptor table that stores descriptors for local segments, giving a task its own set of segment registers. + +Finally, it assigns the newly created task structure, p, to the task array at index "nr." This effectively makes the new task available for scheduling. + + + +"sys_fork" finds an empty process ID using the search loop in `_find_empty_process`, then it invokes `_copy_process` to clone the parent's kernel context to the new process. This sets up a complete environment for the new process to run independently from the parent, but initially as a nearly identical copy.