--- 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.