天天看点

IMX6Solo启动流程-Linux 内核启动 七

写在前头

*.版权声明:本篇文章为原创,可随意转载,转载请注明出处,谢谢!另我创建一个QQ群82642304,欢迎加入!

*.目的:整理一下RIotBoard开发板的启动流程,对自己的所学做一个整理总结,本系列内核代码基于linux-3.0.35-imx。

*.备注:整个系列只是对我所学进行总结,记录我认为是关键的点,另我能力有限,难免出现疏漏错误,如果读者有发现请多指正,以免我误导他人!

接上篇分析:

/*
     * The following calls CPU specific code in a position independent
     * manner.  See arch/arm/mm/proc-*.S for details.  r10 = base of
     * xxx_proc_info structure selected by __lookup_processor_type
     * above.  On return, the CPU will be ready for the MMU to be
     * turned on, and r0 will hold the CPU control register value.
     */
    ldr r13, =__mmap_switched       @ address to jump to after
                        @ mmu has been enabled
    adr lr, BSYM(f)            @ return (PIC) address
    mov r8, r4              @ set TTBR1 to swapper_pg_dir
 ARM(   add pc, r10, #PROCINFO_INITFUNC )
 THUMB( add r12, r10, #PROCINFO_INITFUNC    )
 THUMB( mov pc, r12             )
:  b   __enable_mmu
ENDPROC(stext)
           

注释里解释的十分清楚。

1. 将__mmap_switched的地址保存在r13,然后将返回地址设置成

b __enable_mmu

然后保存页表地址到r8,跳转到struct proc_info_list->__cpu_flush。

2. struct proc_info_list->__cpu_flush的定义在arch/arm/mm/proc-**.S,对我来说就是arch/arm/mm/proc-v7.S:

/*
     * Match any ARMv7 processor core.
     */
    .type   __v7_proc_info, #object
__v7_proc_info:
    .long         @ Required ID value
    .long         @ Mask for ID
    ALT_SMP(.long \
        PMD_TYPE_SECT | \
        PMD_SECT_AP_WRITE | \
        PMD_SECT_AP_READ | \
        PMD_FLAGS_SMP)
    ALT_UP(.long \
        PMD_TYPE_SECT | \
        PMD_SECT_AP_WRITE | \
        PMD_SECT_AP_READ | \
        PMD_FLAGS_UP)
    .long   PMD_TYPE_SECT | \
        PMD_SECT_XN | \
        PMD_SECT_AP_WRITE | \
        PMD_SECT_AP_READ
    W(b)    __v7_setup
    .long   cpu_arch_name
    .long   cpu_elf_name
    .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS
    .long   cpu_v7_name
    .long   v7_processor_functions
    .long   v7wbi_tlb_fns
    .long   v6_user_fns
    .long   v7_cache_fns
    .size   __v7_proc_info, . - __v7_proc_info
           

即跳转到__v7_setup,它的作用注释里面页解释清楚:

Initialise TLB, Caches, and MMU state ready to switch the MMU

arm V7内核,架构相关,我没有继续研究。

执行完__v7_setup后,由于之前我们已经赋值好lr寄存器的值,所以跳转之后,就是继续跳转到__enable_mmu函数。

3. __enable_mmu函数在head.S中定义,它的作用就是开启MMU,在该函数的最后汇编代码片段为

mov r3, r13
    mov pc, r3
           

我们可以看到跳转到里r13寄存器里面保存的值,在之前r13寄存器保存的值是__mmap_switched,这是一个链接地址,跳转到这边后就跳出平等映射代码区域。

4. __mmap_switched的定义在head-common.S中:

/*
 * The following fragment of code is executed with the MMU on in MMU mode,
 * and uses absolute addresses; this is not position independent.
 *
 *  r0  = cp#15 control register
 *  r1  = machine ID
 *  r2  = atags/dtb pointer
 *  r9  = processor ID
 */
    __INIT
__mmap_switched:
    adr r3, __mmap_switched_data

    ldmia   r3!, {r4, r5, r6, r7}
    cmp r4, r5              @ Copy data segment if needed
:  cmpne   r5, r6
    ldrne   fp, [r4], #4
    strne   fp, [r5], #4
    bne b

    mov fp, #0              @ Clear BSS (and zero fp)
:  cmp r6, r7
    strcc   fp, [r6],#4
    bcc b

 ARM(   ldmia   r3, {r4, r5, r6, r7, sp})
 THUMB( ldmia   r3, {r4, r5, r6, r7}    )
 THUMB( ldr sp, [r3, #16]       )
    str r9, [r4]            @ Save processor ID
    str r1, [r5]            @ Save machine type
    str r2, [r6]            @ Save atags pointer
    bic r4, r0, #CR_A           @ Clear 'A' bit
    stmia   r7, {r0, r4}            @ Save control register values
    b   start_kernel
ENDPROC(__mmap_switched)
           

清除BSS段,跳转到start_kernel。

start_kernel定义在init/main.c中,就是内核启动的第二阶段(C语言)。

在该函数里面做着大量的初始化工作,是一个非常重要的函数。

网络上有许多关于该函数的分析。我后续也会慢慢分析,但是我打算不按照它的执行流程来分析,而是尽量按照功能/模块来分析。

如果需要研究它的执行流程,建议参考网络上其他文章。

总结

创建页表之后的代码理解起来比较容易,我就没有详细分析。

参考

暂无

继续阅读