Arm-linux kernel Start-up process Analysis (2)-start_kernel before the second step

Source: Internet
Author: User

The previous blog analyzed the first dozens of compilations of the arm kernel launch,
Analysis today, but today only analyzes Stext in a compilation, as follows:
BL __create_page_tables

Let's see how the page table is initialized before the MMU starts early in kernel.

#ifdef CONFIG_ARM_LPAE/* LPAE requires an additional page for the PGD */#define PG_DIR_SIZE 0x5000#define Pmd_order 3#else#define pg_dir_size 0x4000#define pmd_order 2#endif ... Macro Pgtbl, RD, Phys add \rd, \phys, #TEXT_OFFSET-pg_dir_size. Endm.....__create_page_tables://According to an analysis of the previous blog post, R8 stores  The physical start address of the SDRAM (my board 0x80000000)//PGTBL macro gets 0x80008000 below the 16K address space as a page Table Space//arm page Table page is 4 bytes, complete the virtual address space 4GB 1MB Mapping,//Total need 4 X    4096 bytes Page Table space//You can see that a single page is completed by a virtual address and physical address high 12-bit conversion.    The low 20-bit address (address within 1M) offsets are consistent. PGTBL R4, R8 @ Page Table address/* Clear the Swapper page Table///////////////////16bytes page Empty mov r0, r4 mov r3, #0 add R6, R0, #PG_DIR_SIZE1: STR R3, [r0], #4 str R3, [r0], #4 str R3, [R0], #4 s     TR R3, [R0], #4 teq r0, R6 BNE 1b//If you define CONFIG_ARM_LPAE, add a second page table before PGD and PMD, here is an unknown scenario #ifdef CONFIG_ARM_LPAE/* * Build the PGD table (first level) to the PMD table.     A PGD * entry is 64-bit wide. */MOV R0, r4 add R3, R4, #0x1000 @ First PMD table address Orr R3, R3, #3 @ PGD block type mov r6, #4  @ PTRS_PER_PGD mov R7, #1 << (55-32) @ l_pgd_swapper1:str R3, [R0], #4 @ set Bottom    PGD entry Bits str R7, [r0], #4 @ set top PGD entry bits add R3, R3, #0x1000 @ Next PMD table Subs R6, R6, #1 bne 1b add R4, R4, #0x1000 @ point to the PMD tables#endif//According to an analysis of the previous blog post, R10 stores the CPU Proce  Ssor_type_list (processor information structure), get the CPU Mmuflags LDR R7, [R10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags/* * Create identity     Mapping to cater for __enable_mmu.     * This identity mapping is removed by Paging_init ().        /////First establish a flat mapping of 1M space containing the turn_mmu_on function (virt addr = phy addr)//turn_mmu_on is not far from stext, so the actual completion of the horizontal mapping of 0x8000000-0x81000000 space Old method, previous post analysis, get PHY to VIRT offset ADR r0, __turn_mmu_on_loc ldmia r0, {R3, R5, R6} Sub R0, R0, R3 @ VI Rt->phys offset//Get turn_mmu_on Physical Address    Add R5, R5, R0 @ Phys __turn_mmu_on add R6, R6, R0 @ Phys __turn_mmu_on_end//due to 1-page mapping 1M space, so sect Ion_shift 20//Right 20 bit, R5,R6 represents the segment address space in the Page table subscript (page) MOV R5, R5, LSR #SECTION_SHIFT mov r6, R6, LSR #SECTION_SHIFT/ /r5 left 20 bits, gets the base address of the page, or mmuflags on the CPU, exists R3 1:orr R3, R7, R5, LSL #SECTION_SHIFT @ flags + Kernel base//R3 value stored in page table space (R4 start) (r5<<4) in the page table//due to a page in 4bytes, so pmd_order=4 str R3, [R4, R5, LSL #PMD_ORDER] @ Identity mapping//R5 and R6 apart    Multiple 1M, you need to fill in multiple page tables. Because the turn_mmu_on function is very short, it must be within 1M, where R5=R6 CMP R5, R6 Addlo R5, R5, #1 @ next Section Blo 1b/* now     Setup the Pagetables kernel Direct * mapped region. ////This establishes a linear map of the kernel entire mirror, ((0x80000000-0x80000000+kernel_end)-(0xc0000000-0xc0000000+kernel_end))// Open MMU after the implementation of the link address (0xc0008000) with the running address (0xc0008000) of the Unified MOV r3, PC MOV r3, R3, LSR #SECTION_SHIFT Orr R3, R7, R3, LSL #SE Ction_shift//The physical starting address of the 1M space is stored in the corresponding virtual Address page in the page table add R0, R4, # (Kernel_start& 0xff000000) >> (section_shift-pmd_order) str R3, [R0, # (Kernel_start & 0x00f00000) >> Section_    SHIFT) << pmd_order]! Ldr R6, = (kernel_end-1) add R0, R0, #1 << pmd_order add R6, R4, R6, LSR # (Section_shift-pmd_order) 1:cmp R0, R6 add R3, R3, #1 << section_shift strls R3, [R0], #1 << pmd_order bls 1b#ifdef Config_xip_kern     EL/* * Map some RAM to cover our. Data and. BSS areas. */Add R3, R8, #TEXT_OFFSET Orr R3, R3, R7 add R0, R4, # (KERNEL_RAM_VADDR & 0xff000000) >> (section_sh    Ift-pmd_order) str R3, [R0, # (KERNEL_RAM_VADDR & 0x00f00000) >> (Section_shift-pmd_order)]! Ldr R6, = (_end-1) add R0, R0, #4 add R6, R4, R6, LSR # (Section_shift-pmd_order) 1:cmp r0, R6 add R3, R3, #1 << strls R3, [R0], #4 BLS 1B#ENDIF/* * Then map boot params address in R2 or the first 1MB (2MB W ITH LPAE) * of RAM if boot params address is not speciFied.    *//The 1M address space containing the boot params is linear mapped to facilitate analysis of args in Start_kernel//According to the previous blog post analysis, R2 stored in the bootloader of the params base address (my board in 0x80000100) So the 1M space is 0x80000000-0x81000000, mapped to 0xc0000000-0xc1000000 mov r0, r2, LSR #SECTION_SHIFT movs r0, r0, LSL #SECTION     _shift Moveq r0, R8 Sub R3, R0, R8 add R3, R3, #PAGE_OFFSET add R3, R4, R3, LSR # (Section_shift-pmd_order) Orr R6, R7, R0 str R6, [r3]//If you need to debug the early serial port output, where I am mapping the I/O space, so as to achieve the operation of the serial controller, here is an unknown solution. #ifdef config_debug_ll#if!defined (CONFIG_DEBUG_ICEDCC) &&!defined (config_debug_semihosting)/* * Map in I     O space for serial debugging.     * This allows debug messages to be output * via a serial console before paging_init.  */Addruart R7, R3, R0 mov r3, R3, LSR #SECTION_SHIFT mov r3, R3, LSL #PMD_ORDER add r0, R4, R3 RSB R3, R3,  #0x4000 @ ptrs_per_pgd*sizeof (LONG) CMP R3, #0x0800 @ limit to 512MB movhi R3, #0x0800 add R6,  R0, R3 mov r3, R7, LSR #SECTION_SHIFT  Ldr R7, [R10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags Orr R3, R7, R3, LSL #SECTION_SHIFT #ifdef CONFIG_ARM_LPAE mov R7 , #1 << (54-32) @ xn#else Orr R3, R3, #PMD_SECT_XN #endif1:str R3, [R0], #4 #ifdef config_arm_lpae str r 7, [R0], #4 #endif add R3, R3, #1 << section_shift cmp r0, R6 blo 1b#else/* CONFIG_DEBUG_ICEDCC | |  Config_debug_semihosting */* We don ' t need any serial debugging mappings */Ldr R7, [R10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags#endif#if defined (config_arch_netwinder) | | Defined (config_arch_cats)/* * If we ' re using the Netwinder or CATS, we also need to map * in the 16550-type SE Rial port for the debug messages */Add r0, R4, #0xff000000 >> (Section_shift-pmd_order) Orr R3, R7, #0x 7c000000 STR R3, [r0] #endif #ifdef CONFIG_ARCH_RPC/* * Map in screens at 0x02000000 & Screen2_base * Simi  Lar reasons here-for Debug.     This was * only for Acorn RISCPC architectures. */Add R0, R4, #0x02000000 >> (Section_shift-pmd_order) Orr R3, R7, #0x02000000 str R3, [r0] add r0, R4, #0xd80000 >> (Section_shift-pmd_order) str R3, [r0] #endif #endif#ifdef config_arm_lpae Sub R4, R4, #0x1000 @ Poi    NT to the PGD TABLE#ENDIF mov pc, Lrendproc (__create_page_tables). ltorg. Align__turn_mmu_on_loc:. Long. . Long __turn_mmu_on. Long __turn_mmu_on_end
Create_page_table completed 3 types of address mapping for the page table space to fill in:
(1) Flat mapping of the 1M space where the turn_mmu_on is located
(2) linear mapping of kernel image
(2) linear mapping of the 1M space where the Bootparams is located


The Physical address space and virtual address space mapping diagram are as follows:



For these 3 address space mappings, I think there are 3 areas worth thinking about:


(1) Why does the turn_mmu_on want to do a flat mapping?
turn_mmu_on I will analyze the next blog post, mainly to complete the operation to open the MMU.
then why do you make a flat map at turn_mmu_on?
It can be imagined that before executing the MMU command, the CPU refers to the turn_mmu_on in the vicinity of 0x80008000.
If you just do a linear mapping of kernel image, the address that the CPU sees will change when you execute the MMU command.
Turn_mmu_on is near 0xc0008000 for the CPU and is unpredictable for the CPU near 0x80008000.
But the CPU does not know these, it just follow the address of the instructions, execute instructions.
So do not do turn_mmu_on ping mapping (virt addr = phy addr), turn_mmu_on operation after opening the MMU is completely unknowable.
Complete turn_mmu_on mapping, we can at the end of turn_mmu_on the MMU has been turned on stability, modify the PC to 0xc0008000 near, you can solve the jump from 0x8xxxxxxx to 0xcxxxxxxx.

(2) kernel image load address why is it in 0x****8000?
Parses the kernel Image linear mapping section, which is a good understanding,
Kernel Compile the link when the entry address is 0xc0008000 (Page_offset + text_offset), But its physical address is not equal to the virtual address of its link, and the linear map of image implements its run address equal to the link address. The
Kernel each page of the table maps 1M, so the entry completes the mapping in the (0x80000000-->0xc0000000) mapping page table. The 1M internal offset of the physical address and the virtual address must be the same. The
kernel defines text_offset = 0x8000. So the physical address that is loaded must be 0x****8000.
In this case, after opening the MMU, access the command near 0xc0008000, the MMU can correctly map the instructions near the 0x****8000 according to the TLB.

(3) Bootparams and kernel entrance is in the same 11 m space, bootparams linear mapping operation is redundant?
Based on the analysis of the second problem, kernel image can be loaded into any 0x****8000 of the SDRAM address space.
The Bootparams address is specified in bootloader and then told to Kernel.
There is a case where the SDRAM start address is added to the 0x80000000,bootparams starting address of 0x80000100.
But kernel image I loaded into 0x81008000, you can see, then bootparams and kernel image in different 11 m space
It is still necessary to bootparams a separate linear mapping operation.


This is what I think about create_page_table 3 questions, if you have any other questions, welcome message discussion, study together.


Today, the TLB is ready to turn on themmu!.


Start_kernel before the remainder of the Assembly how to open the MMU, the next analysis.

Arm-linux kernel Start-up process Analysis (2)-start_kernel before the second step

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.