--- title: Linux Kernel, syscalls date: 2023-11-11T01:22:30Z 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()` "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.