blog/content/posts/2022-11-19-Linux-Kernel-sys...

3.4 KiB

title date slug description
Linux Kernel, syscalls 2022-11-19T linux-kernel-sys-fork

sys_fork()

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

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.