First, the experimental process
Open the shell using the lab building virtual machine
CD linuxkernel/ -kernel linux-3.18. 6/arch/x86/boot/bzimage-initrd rootfs.img
The kernel boots into the menu program. The following is a boot process that uses GBD to track the kernel:
gdb (gdb) file Linux-3.18. 6/vmlinux # Targe remote before loading symbol table (GDB) in GDB interface target remote:1234 # To establish a connection between GDB and Gdbserver, press C to allow the Linux on QEMU to continue running (GDB)break Start_kernel # Breakpoint setting can be before target remote, can also be in the following
The-S and-s options are represented here respectively:
-S freeze CPU at startup (with ' C ' to start execution).
-S shorthand for-gdb tcp::1234 If you do not want to use port 1234, you can use-GDB tcp:xxxx to replace the-s option.
Open a separate Shell window and enter GDB. Then enter file Linux-3.18.6/vmlinux to load the symbol table before Targe remote in the GDB interface;
Target remote:1234, establish a connection between GDB and Gdbserver, and press C to keep the Linux on qemu running.
gdb (gdb) file Linux-3.18. 6/vmlinux # Targe remote before loading symbol table (GDB) in GDB interface target remote:1234 # To establish a connection between GDB and Gdbserver, press C to allow the Linux on QEMU to continue running (GDB)break Start_kernel # breakpoints can be set before target remote or after
As you can see, the kernel boot stops at the Start_kernel process, which is a long initialization process before starting with power on. x86 the first action cs:eip=ffff:0000h the CPU starts (converted to a physical address of 000ffff0h, because the 16-bit CPU has 20 address lines), the location of the BIOS program, where the computer simply executes the binary instructions, there is no real process at this time. Then it runs to the second breakpoint, Rest_init, which is the last function of the Start_kernel call. Set the associated breakpoint, where we will conclude that the function breaks Start_kernel and rest_init. Continue the program and observe the code at the breakpoint.
Second, the execution of Start_kernel function
The system has had some minimal initialization before entering the Start_kernel function, and further research involves many hardware-related and programming languages. The kernel enters the C language section, which completes most of the kernel's initialization work. In fact, the Start_kernel function can be seen as the main function of the kernel. This function is in INIT/MAIN.C:
void __init start_kernel (void) { char *command_line; Char *after_dashes; /* * need to run as early as possible, to initialize the * LOCKDEP hash: */ L Ockdep_init (); Set_task_stack_end_magic (&init_task); SMP_SETUP_PROCESSOR_ID (); Debug_objects_early_init ();
The first is to call the Lockdep_init function
voidLockdep_init (void) { inti; /** Some architectures has their own start_kernel () * Code which calls Lockdep_init (), while we also * Call Lockdep_init () from the Start_kernel () itself, * and we want to initialize the hashes only once:*/ if(lockdep_initialized)return; for(i =0; i < classhash_size; i++) Init_list_head (classhash_table+i); for(i =0; i < chainhash_size; i++) Init_list_head (chainhash_table+i); Lockdep_initialized=1; }
At the end of the Start_kernel function, the Rest_init function is called for subsequent initialization, generating a process of number one.
Static void __init_refok rest_init (void) { int pid; Rcu_scheduler_starting (); /* * We need to spawn Init first so it obtains PID 1, however * The init task would end up wanting to CRE Ate Kthreads, which, if * We schedule it before we create Kthreadd, would OOPS. */ kernel_thread (Kernel_init, NULL, clone_fs); Numa_default_policy (); = Kernel_thread (Kthreadd, NULL, CLONE_FS | Clone_files);
Pid= Kernel_thread (Kthreadd, NULL, CLONE_FS | Clone_files); This line of code is to create a clean kernel thread so that all other kernel threads later copy it and create it to make it easier to create threads.
= Find_task_by_pid_ns (PID, &Init_pid_ns); Rcu_read_unlock (); Complete (&kthreadd_done) ; /* * The boot idle thread must execute schedule () * At least once to get things moving: */ Init_idle_bootup_task (current);
Init_idle_bootup_task (current); This line of code is the scheduler that initializes the idle process so that the idle process knows how to dispatch the process in the Task list. Current is the structure that points to the currently idle task.
schedule_preempt_disabled (); /* */cpu_startup_entry (cpuhp_online);
This line of code is called the Process Scheduler function schedule, the primary initialization scheduler can switch back to idle tasks. and increase the kernel preemption count.
Iii. Summary
In this experiment, I analyzed the startup process of the Linux system. The process that was initially executed is the No. 0 process Init_task, which is statically generated, the memory stack is fixed in place, and some initialization work is performed. Until Start_kernel starts calling execution Sched_init (), the No. 0 process is initialized to a idle task by the Init_idle (current, smp_processor_id ()) process, It becomes the same as the process in the last experiment, through a while loop executes continuously, as long as there is no other process in the running stack it executes, the loop constantly detects whether there are other processes in the running stack and dispatch through the schedule function.
where the idle process is generated as: idle is a process with a PID number of 0. Its predecessor was the first process created by the system and the only one that was not produced by fork (). It is in this experiment, specifically by the Start_kernel function in the init/main.c set_task_stack_end_magic (&init_task) This line began to implement. The init_task is the process of manually created Pcb,pid=0, which is the final idle process.
The 1th process is generated as: and to Kernel_thread (Kernel_init, NULL, Clone_fs), the pid=1 1th process is established by fork (), Also known as the Init process, which is the first user-state process, it will continue to complete the remaining initialization work and become the ancestor of all other processes in the system. With the creation of process number 1th, as init_idle_bootup_task (current) and other functions, process No. 0 becomes the idle process. The idle process is used when the system has no processes to execute. So in Start_kernel and Rest_init, the process of number No. 0 was created, which was established during the initialization of the system and persisted during the system's operation, while process No. 0 generated the 1th process, as well as numerous subsequent processes. Finally entered the cpu_startup_entry. This is actually called the Cpu_idle. In fact, it is in the while loop called the No. 0 process.
Although in the experiment I did not understand the Linux system startup process, but the understanding of Linux system is not deep, need to further strengthen.
Liu Shuai
Original works reproduced please indicate the source
"Linux kernel Analysis" MOOC course http://mooc.study.163.com/course/USTC-1000029000
Linux kernel analysis Trace analysis boot process of Linux kernel