Linux kernel startup process analysis
Link: https://blog.51cto.com/min2000/8840552
-
Linux kernel self-extraction process
After uboot completes system booting, it executes the command in the environment variable bootm; that is, it transfers the Linux kernel into the memory and calls the do_bootm function to start the kernel and jump to the starting position of the kernel. If the kernel has not been compressed, it will be started directly; if the kernel has been compressed, it needs to be decompressed. There is a decompression program in the header of the compressed kernel.
The source code location of the first file of the compressed kernel entry is /kernel/arch/arm/boot/compressed/head.S. It will call the decompress_kernel() function to decompress. After decompression is completed, the message "Uncompressing Linux...done, booting the kernel" will be printed. After decompression is completed, call the gunzip() function (or unlz4(), bunzip2(), or unlz()) to place the kernel at the specified location and start the kernel.
2. Linux kernel startup preparation phase
According to the kernel link script /kernel/arch/arm/kernel/vmlinux.lds, the kernel entry function is stext (/kernel/arch/arm/kernel/head.S). After the kernel decompression is completed, the decompression code calls the stext function to start the kernel.
ENTRY(stext)
setmodePSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode@ and irqs disabled
mrcp15, 0, r9, c0, c0 @ 获得处理器ID,并存储在r9寄存器中
bl__lookup_processor_type @ 结果返回:描述处理器结构体的地址 r5=procinfo ,处理器ID号 r9=cpuid
movsr10, r5 @ invalid processor (r5=0)?判断内核是否支持该处理器
beq__error_p @ yes, error 'p'
bl__lookup_machine_type @结果返回:描述机器(开发板)的结构体地址 r5=machinfo
movsr8, r5 @ invalid machine (r5=0)?判断内核是否支持该机器(开发板)
beq__error_a @ yes, error 'a'
bl__vet_atags @检查uboot给内核的传参ATAGS格式是否正确
bl__create_page_tables @建立虚拟地址映射页表
ldrr13, __switch_data @ address to jump to after
(1) Turn off IRQ and FIQ interrupts and enter SVC mode. Call the setmode macro to implement;
(2) Verify the processor ID and check whether the kernel supports the processor; if not, stop starting the kernel. Call the __lookup_processor_type function to implement;
(3) Verify the machine code and check whether the kernel supports the machine; if not, stop starting the kernel. Call the __lookup_machine_type function to implement;
(4) Check whether the ATAGS format passed by uboot to the kernel is correct and call the __vet_atars function to implement;
(5) Establish a virtual address mapping page table. The page table created here is a coarse page table, which is used in the early stage of kernel startup. Linux has finer requirements for memory management and will subsequently re-establish finer page tables. Call the __create_page_tables function to implement.
(6) Jump to execute the __switch_data function, in which __mmap_switched is called to complete the final preparations.
1) Copy the data segment and clear the bss segment in order to build a C language running environment;
2) Save the processor ID number, machine code, and uboot parameter address to the kernel;
3) b start_kernel jumps to the kernel initialization phase.
__switch_data:
.long__mmap_switched
..........................................................
__mmap_switched:
adrr3, __switch_data + 4
ldmiar3!, {r4, r5, r6, r7}
cmpr4, r5@ Copy data segment if needed
1:cmpner5, r6
ldrnefp, [r4], #4
strnefp, [r5], #4
bne1b
movfp, #0@ Clear BSS (and zero fp)
1:cmpr6, r7
strccfp, [r6],#4
bcc1b
ARM(ldmiar3, {r4, r5, r6, r7, sp})
THUMB(ldmiar3, {r4, r5, r6, r7})
THUMB(ldrsp, [r3, #16])
strr9, [r4]@ Save processor ID
strr1, [r5]@ Save machine type
strr2, [r6]@ Save atags pointer
bicr4, r0, #CR_A@ Clear 'A' bit
stmiar7, {r0, r4}@ Save control register values
bstart_kernel
ENDPROC(__mmap_switched)
3. Linux kernel initialization phase
This phase starts with the start_kernel function. The start_kernel function is the entry function for all Linux platforms to enter the system kernel initialization. Its main job is to complete the remaining initialization work related to the hardware platform. After a series of kernel-related initializations, it calls the first user process init and waits for its execution. At this point, the entire kernel startup is completed.
3.1 The main work of the start_kernel function
The start_kernel function mainly completes kernel-related initialization work. Specifically includes the following parts:
(1) Kernel architecture and general configuration related initialization
(2) Memory management related initialization
(3) Process management related initialization
(4) Process scheduling related initialization
(5) Network subsystem management
(6) Virtual file system
(7) File system
3.2 Key functions in start_kernel function flow
(1) setup_arch(&command_line) function
The initialization function related to the kernel architecture is a very important initialization step. This includes the initialization of processor-related parameters, acquisition and pre-processing of kernel startup parameters (tagged list), and early initialization of the memory subsystem.
Command_line is essentially the command line startup parameter passed by uboot to the kernel, that is, the value of the environment variable bootargs in uboot. If the value of bootargs in uboot is empty, command_line = default_command_line is the default command line parameter in the kernel. Its value is configured in the .config file and corresponds to the CONFIG_CMDLINE configuration item.
(2) setup_command_line, parse_early_param and parse_args functions
These functions complete the parsing and saving of command line parameters. For example, cmdline = console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3; is parsed into the following four parameters:
console=ttySAC2,115200 //Specify the serial port device number of the console and its baud rate
root=/dev/mmcblk0p2 rw //Specify the path of the root file system rootfs
init=/linuxrc //Specify the first user process init Path
rootfstype=ext3 //Specify the type of root file system rootfs
(3) sched_init function
Initialize the process scheduler, create a run queue, and set the empty thread of the current task.
(4)rest_init function
The main work of the rest_init function is as follows:
1) Call the kernel_thread function to start two kernel threads, namely: kernel_init and kthreadd. The prepare_namespace function is called in the kernel_init thread to mount the root file system rootfs; then the init_post function is called to execute init, the first user process under the root file system rootfs. The user process has four alternatives. If the path of init in command_line is wrong, the alternative plan will be executed. The first backup: /sbin/init, the second backup: /etc/init, the third backup: /bin/init, the fourth backup: /bin/sh.
2) Call the schedule function to start the kernel scheduling system;
3) Call the cpu_idle function to start the idle process idle and complete the kernel startup.
Recently, many friends have asked me for some essential information for programmers, so I dug out the treasures at the bottom of the box and shared them with everyone for free!
Scan the QR code of the poster to get it for free.