I am trying to understand the init process in the linux kernel which is the first process and is statically initialized with the INIT_TASK macro.
161 #define INIT_TASK(tsk) \
162 { \
163 .state = 0, \
164 .stack = &init_thread_info, \
165 .usage = ATOMIC_INIT(2), \
166 .flags = PF_KTHREAD, \
167 .prio = MAX_PRIO-20, \
168 .static_prio = MAX_PRIO-20, \
169 .normal_prio = MAX_PRIO-20, \
170 .policy = SCHED_NORMAL, \
171 .cpus_allowed = CPU_MASK_ALL, \
172 .nr_cpus_allowed= NR_CPUS, \
173 .mm = NULL, \
174 .active_mm = &init_mm, \
175 .se = { \
176 .group_node = LIST_HEAD_INIT(tsk.se.group_node), \
177 }, \
178 .rt = { \
179 .run_list = LIST_HEAD_INIT(tsk.rt.run_list), \
180 .time_slice = RR_TIMESLICE, \
181 }, \
182 .tasks = LIST_HEAD_INIT(tsk.tasks), \
183 INIT_PUSHABLE_TASKS(tsk) \
184 INIT_CGROUP_SCHED(tsk) \
185 .ptraced = LIST_HEAD_INIT(tsk.ptraced), \
186 .ptrace_entry = LIST_HEAD_INIT(tsk.ptrace_entry), \
187 .real_parent = &tsk, \
188 .parent = &tsk, \
189 .children = LIST_HEAD_INIT(tsk.children), \
190 .sibling = LIST_HEAD_INIT(tsk.sibling), \
191 .group_leader = &tsk, \
192 RCU_POINTER_INITIALIZER(real_cred, &init_cred), \
193 RCU_POINTER_INITIALIZER(cred, &init_cred), \
194 .comm = INIT_TASK_COMM, \
195 .thread = INIT_THREAD, \
196 .fs = &init_fs, \
197 .files = &init_files, \
198 .signal = &init_signals, \
199 .sighand = &init_sighand, \
200 .nsproxy = &init_nsproxy, \
201 .pending = { \
202 .list = LIST_HEAD_INIT(tsk.pending.list), \
203 .signal = {{0}}}, \
204 .blocked = {{0}}, \
205 .alloc_lock = __SPIN_LOCK_UNLOCKED(tsk.alloc_lock), \
206 .journal_info = NULL, \
207 .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \
208 .pi_lock = __RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock), \
209 .timer_slack_ns = 50000, /* 50 usec default slack */ \
210 .pids = { \
211 [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \
212 [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID), \
213 [PIDTYPE_SID] = INIT_PID_LINK(PIDTYPE_SID), \
214 }, \
215 .thread_group = LIST_HEAD_INIT(tsk.thread_group), \
216 INIT_IDS \
217 INIT_PERF_EVENTS(tsk) \
218 INIT_TRACE_IRQFLAGS \
219 INIT_LOCKDEP \
220 INIT_FTRACE_GRAPH \
221 INIT_TRACE_RECURSION \
222 INIT_TASK_RCU_PREEMPT(tsk) \
223 INIT_CPUSET_SEQ \
224 INIT_VTIME(tsk) \
225 }
But I am not able to figure out
how it will be executed?
Where it is scheduled and
which lines of code in the linux kernel start executing immediately when we say we have scheduled this init_task task? Is there any function which it calls?
Init is started by the kernel during the booting process; a kernel panic will occur if the kernel is unable to start it. Init is typically assigned process identifier 1.
Init is the parent of all processes, executed by the kernel during the booting of a system. Its principle role is to create processes from a script stored in the file /etc/inittab. It usually has entries which cause init to spawn gettys on each line that users can log in.
The machine's BIOS or boot microcode hundreds and runs a boot loader. Boot loader finds the kernel image on the disk and loads it into memory, to start the system. The kernel initializes the devices and their drivers.
The __init keyword tells the linker to place the code in a dedicated section into the kernel object file. This section is known in advance to the kernel, and freed when the module is loaded and the init function finished.
The kernel calls "init" as one of the very last things it does during kernel initialization. The function kernel_init()
in init/main.c has the logic.
You will notice that the kernel tries four different combinations of init, and expects one of them to succeed. You will also notice that you can override what the kernel executes on startup by feeding the kernel command line parameter "init". So, you can say, for example, init=/bin/mystartup on the kernel command line and start your own custom application instead of the default /sbin/init. Notice also that on most modern systems, even embedded systems, /sbin/init is a soft link that points to the real executable.
To more generally answer your question, study this source file (main.c) you can see virtually all of the details of Linux kernel initialization, after the low-level assembly stuff and platform initialization, which, beyond the educational value, you shouldn't have to touch nor care about much.
The main mechanism is to call do_execve()
with fixed arguments of argv_init
and envp_init
. The elf file is parsed and initial program counter (PC) is set as per the file. All memory management (mm) pages are mapped to the disks backing store. The code is set to run. On the initial PC fetch when it is scheduled, a page fault is generated which reads the first code page into memory. This is the same as any other execve()
call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With