The previous period of time transplant Uboot carefully studied the Uboot start-up process, recently unable to endure loneliness, and want to kernel.
Uboot Start Process Analysis Post links are as follows:
http://blog.csdn.net/skyflying2012/article/details/25804209
Kernel startup process generally does not require us to modify, research this for writing driver is not much help, but to understand the entire Linux architecture, various mechanisms are very useful.
As the heart Chicken soup said, only understand how a person grows, can see what he is what kind of person (Chinese bad, general meaning so.) )
Only when we know how kernel is started can we really understand kernel
As an embedded worker, I think I can not just limit to a module driver, but should go deep into the sea of kernel to be proud to swim!
Learning to start the process, I am guided by the principle of ask why, I hope to study plainly, but also because of the level of limited, there are many flaws
Share the blog, I hope we have a lot of exchanges, hard finishing, if necessary reprint, please also indicate the source.
This period of time mainly to learn Start_kernel before the launch code, just a few hundred lines of compilation, but there are a lot of essence.
Start_kernel before the code is divided into 3 parts to analyze, today first to learn the first dozens of lines!
Kernel version number: 3.4.55
In Arch/arm/kernel/head. S, as follows:
. Arm __headentry (stext) THUMB (ADR R9, Bsym (1f)) @ Kernel is always entered in arm. Thumb (bx R9) @ If This is a Thumb-2 kernel, thumb (. thumb) @ Switch to Thumb now. THUMB (1:)//Processor enters SVC mode, shutdown interrupt SetMode psr_f_bit | Psr_i_bit | Svc_mode, R9 @ ensure svc MODE @ and IRQs disabled//Get processor ID MRC P15, 0, R9, C0, C0 @ ge T processor ID BL __lookup_processor_type @ r5=procinfo r9=cpuid//proc_type_list pointer exists in R10, if NULL, error _p movs R10, R5 @ Invalid processor (r5=0)? THUMB (IT eq) @ Force fixup-able Long Branch encoding beq __error_p @ Yes, error ' P '//config_arm _lpae not quite understand the meaning, I use the processor configuration file did not select the item, interested friends can study under #ifdef config_arm_lpae MRC P15, 0, R3, C0, C1, 4 @ Read id_mmfr0 and R3 , R3, #0xf @ Extract VMSA support CMP r3, #5 @ long-descriptor translation table format? THUMB (it lo) @ Force fixup-able Long BrancH encoding blo __error_p @ only classic page table Format#endif#ifndef Config_xip_kernel//Get Physical address and virtual address off Set, exists in R8 ADR R3, 2f Ldmia R3, {r4, R8} Sub R4, R3, R4 @ (phys_offset-page_offset) Add R8, R8, R4 @ phys_offset#else//definition Config_xip_kernel,offset for Phys_offset ldr R8, =phys_offset @ always constant In this case#endif/* * R1 = machine no, r2 = Atags or DTB, * r8 = phys_offset, R9 = cpuid, R10 = ProcInfo *///Bootloader The tags sent to the parameters to check BL __vet_atags
The entry function for kernel, where the entry address is, needs to be determined based on the connection script.
In ARCH/ARM/KERNEL/VMLINUX.LDS.S, as follows:
Output_arch (ARM) ENTRY (stext) #ifndef __armeb__jiffies = jiffies_64; #elsejiffies = jiffies_64 + 4; #endifSECTIONS { ... #ifdef config_xip_kernel . = Xip_virt_addr (config_xip_phys_addr); #else . = Page_offset + Text_offset; #endif}
The entry function is head. s in the stext, not the use of XIP technology, the entry address is page_offset+text_offset.
./arch/arm/include/asm/memory.h:
#define Page_offset UL (Config_page_offset) menuconfig in config_page_offset = 0xc0000000./arch/arm/makefile: textofs-y: = 0x000 08000textofs-$ (config_arch_clps711x): = 0x00028000# We don ' t want the HTC bootloader to corrupt kernel during resumetextof s-$ (config_pm_h1940): = 0x00108000# SA1111 DMA bug:we don ' t want the kernel to live in precious dma-able memoryifeq ($ (config_arch_sa1100), y) textofs-$ (config_sa1111): = 0x00208000endiftextofs-$ (config_arch_msm7x30): = 0x00208000textofs-$ (config_arch_msm8x60): = 0x00208000textofs-$ (config_arch_msm8960): = 0x00208000......# the Byte Offset of the kernel image in RAM from the start of RAM. Text_offset: = $ (textofs-y)
The entry address is 0xc0008000.
However, in practice, kernel is loaded to the 0x80008000 address to run.
(I use the processor SDRAM physical start address is 0x80000000)
Why is the link address inconsistent with the run address?
After studying the compilation before Start_kernel, you will understand the reason.
In Stext, the start is called to __lookup_processor_type, the code is as follows:
__cpuinit__lookup_processor_type://3 Line Assembly, calculates the offset between the physical address and the virtual address, the existence of R3 ADR R3, __lookup_processor_type_data LDMI A r3, {R4-R6} sub r3, R3, r4 @ Get offset between virt&phys//Get __proc_info_begin Physical Address add R5, R 5, r3 @ Convert virt addresses to//Get __proc_info_end Physical Address add R6, R6, R3 @ Physical Address space Mask CP15 read out the CPUID, in contrast to the value in Proc_type_list 1:ldmia R5, {r3, R4} @ value, mask and R4, R4, R9 @ Mask wanted bits TEQ R3, R4//Consistent return, inconsistent jump to the next proc_type_list, continue to compare beq 2f add R5, R5, #PROC_INFO_SZ @ sizeof (PROC_INFO_LIST) CMP R5, R6 Blo 1b//Match succeeded, R5 save the Proc_type_list pointer, match failed, R5 0 mov R5, #0 @ unkno WN Processor2:mov pc, Lrendproc (__lookup_processor_type)/* Look in <asm/procinfo.h> for information about the __ Proc_info structure. */. Align 2. Type __lookup_processor_type_data,%object__lookup_processor_type_data:. Long. . Long __PROC_Info_begin. Long __proc_info_end. Size __lookup_processor_type_data,. -__lookup_processor_type_data</span>
Because kernel to open the MMU, so kernel compile the link address is a virtual address (physical address after the MMU conversion of the CPU to see the address), not the physical address,
The link determines the absolute address (virtual address) of the variable, but at this stage, the SDRAM address that MMU,CPU sees is its physical address (0x80000000 start).
If running directly, there is a problem with addressing the variable (function addressing is not a problem because the ARM function addressing uses the relative jump instruction b bl)
For example, kernel image in the global variable I link address in 0xc0009000, but at this stage I physical address is in 0x80009000, for the CPU, only on 0x80009000 can find I.
To 0xc0009000 addressing, the program runs out of error.
This is why we understand that the address of the link address load must be consistent.
Kernel current solution is to lookup_processor_type the first 3 lines of the assembly:
ADR R3, __lookup_processor_type_data load __lookup_processor_type_data address (actual run address, here is the physical address) to R3
Ldmia R3, {R4-R6} gets a variable with an address of R3 r3+4 r3+8 to R4,R5,R6.
The value of the address variable is determined at the time of the link, so the link address (virtual address) of the __lookup_processor_type_data is stored in the R4.
Sub R3, R3, R4 R3 are stored in the offset of the physical address from the virtual address.
This is how genius operation Ah!
_proc_info_begin _proc_info_end is defined in the link script and is the end of the. Proc.info.init segment.
In this section is the Proc_info_list struct, which represents the processor-related information, defined as follows:
struct Proc_info_list { unsigned int cpu_val; unsigned int cpu_mask; unsigned long __cpu_mm_mmu_flags;/* used by head. S */ unsigned long __cpu_io_mmu_flags;/* used by head. S */ unsigned long __cpu_flush; /* Used by head. S */ const char *arch_name; const char *elf_name; unsigned int elf_hwcap; const char *cpu_name; struct processor *proc; struct Cpu_tlb_fns *tlb; struct CPU_USER_FNS *user; struct Cpu_cache_fns *cache;};
The paragraph is in the arch/arm/mm/proc-xxx. s in the fill, do not need software staff modification, interested friends can study under.
Lookup_processor_type_data returns to the Stext.
Next, the same method is used to obtain phy&virt offset, there is R8.
Based on my previous analysis of Uboot kernel's blog post (link below: http://blog.csdn.net/skyflying2012/article/details/35787971)
R1 Storage Machine ID,R2 storage atags.
Stext in __vet_atags will do a basic check for atags, the code is as follows:
__vet_atags: tst R2, #0x3 @ aligned? BNE 1f Ldr R5, [R2, #0] //Determine if DTB type #ifdef config_of_flattree ldr R6, =of_dt_magic @ is it a DTB? CMP R5, R6 beq 2f#endif CMP R5, #ATAG_CORE_SIZE @ is first tag Atag_core? Cmpne R5, #ATAG_CORE_SIZE_EMPTY bne 1f LDR R5, [R2, #4] ldr R6, =atag_core CMP R5, R6 BNE 1f //correct tags, return 2: mov pc, LR @ atag/dtb pointer is OK //Error tags, empty r2, return 1: mov r2, #0 mov pc , Lrendproc (__vet_atags)
Check that the tag header 4 byte (size of Tag_core) and the second 4 byte (tag_core type) are correct.
For Stext in the first dozens of lines of the assembly, has been analyzed to complete, summed up the work of what to do:
(1) Set CPU mode
(2) Check if CPUID matches
(3) Get Phy&virt offset
(4) Check atags parameters
This code analyzes this, but it causes me to think about the address of the link address.
Always think that the address of the link address (load address) must be consistent, but did not really think about this problem.
Just as the teacher tells us that the Earth is round, we think the earth is round and not explored.
Why should the link address and the running address of the program be consistent?
My understanding, the link determines the program to run the absolute address, also determined the variables and functions of the absolute address, the load run address is not its link address, the variable is actually stored address changed.
At this point, if the variable is addressed, there will be an unknown result, which is why I can think of.
Usually we compile links are some C language programming, it will inevitably define some global variables, if the link and run address inconsistencies, it will not be properly addressed.
If you want to run and link address inconsistencies, I can think of a way, can only be in the Assembly to try not to involve some absolute address, using PIC location-independent code.
Lenovo previously analyzed the principles of uboot Relocation (blog link: http://blog.csdn.net/skyflying2012/article/details/37660265),
Uboot after relocation, kernel implemented the link address and run address inconsistency before opening the MMU to see what method they used?
(1) uboot Modify the Rel.dyn segment (store all variable addresses) at relocation to relocate all variable addresses to the new run address
(2) The kernel calculates the offset of the running address (physical address) and the link address (virtual address) before opening the MMU, and addresses the variables when addressing them, thus finding the variables normally. After opening the MMU, the hardware mechanism is used to realize the unification of the link and the running address.
So, must the link address be equal to the running address? Not necessarily, embedded most famous uboot kernel is an example!
Analyze this today, the remainder of the Start_kernel before the Assembly will write 2 articles to analyze the study.
Arm-linux kernel Start-up process Analysis (1) First step before-start_kernel