首页 > 代码库 > Tiny4412 Linux 内核启动流程

Tiny4412 Linux 内核启动流程

 Linux内核的启动分为压缩内核和非压缩内核两种,这里我们以压缩内核为例。压缩内核运行时,将运行一段解压缩程序,得到真正的内核镜像,然后跳转到内核镜像运行。此时,Linux进入非压缩内核入口,在非压缩内核入口中,完成各种初始化操作后跳转到C语言入口处运行。主要流程如下所示。

技术分享

1.解压缩内核镜像

解压缩程序通常在arch/arm/boot/compressed/目录中

├── atags_to_fdt.c
├── big-endian.S
├── decompress.c
├── head.S
├── head-sa1100.S
├── head-shark.S
├── head-sharpsl.S
├── head-shmobile.S
├── head-vt8500.S
├── head-xscale.S
├── libfdt_env.h
├── ll_char_wr.S
├── Makefile
├── misc.c
├── mmcif-sh7372.c
├── ofw-shark.c
├── piggy.gzip.S
├── piggy.lzma.S
├── piggy.lzo.S
├── piggy.xzkern.S
├── sdhi-sh7372.c
├── sdhi-shmobile.c
├── sdhi-shmobile.h
├── string.c
└── vmlinux.lds.in

它们经过编译后,生成的内容独立于真正的Linux内核,这部分内容的功能就是初始化环境,解压缩和运行真正的Linux内核。在压缩内核启动时,首先进入arch/arm/boot/compressed目录中的compressed目录中的head.S文件。

start:
                .type   start,#function
                .rept   7
                mov     r0, r0
                .endr
   ARM(         mov     r0, r0          )    
   ARM(         b       1f              )    
 THUMB(         adr     r12, BSYM(1f)   )
 THUMB(         bx      r12             )    
                .word   0x016f2818              @ Magic numbers to help the loader
                .word   start                   @ absolute load/run zImage address
                .word   _edata                  @ zImage end address
 THUMB(         .thumb                  )    
1:              mov     r7, r1                  @ save architecture ID
                mov     r8, r2                  @ save atags pointer  

start是head.S的程序的开始,在此之前都是一些宏定义。在1标号处保存由bootloader传递过来的参数

#ifndef __ARM_ARCH_2__
                /*
                 * Booting from Angel - need to enter SVC mode and disable
                 * FIQs/IRQs (numeric definitions from angel arm.h source).
                 * We only do this if we were in user mode on entry.
                 */
               @获取当前运行模式
                mrs     r2, cpsr                @ get current mode
               @测试是否为usr模式
                tst     r2, #3                  @ not user?
                bne     not_angel
                mov     r0, #0x17               @ angel_SWIreason_EnterSVC
 ARM(           swi     0x123456        )       @ angel_SWI_ARM
 THUMB(         svc     0xab            )       @ angel_SWI_THUMB
not_angel:
                mrs     r2, cpsr                @ turn off interrupts to
                orr     r2, r2, #0xc0           @ prevent angel from running
                msr     cpsr_c, r2
#else
                teqp    pc, #0x0c000003         @ turn off interrupts
#endif

如果内核从angel运行进入的运行模式将是usr mode,这时需要进入svc mode ,并禁止所有FIQ和IRQ中断。这些只有在进入时处于用户模式的时候才会执行。正常情况下,将运行not_angel标号处关闭中断的代码。然后对内核代码进行重定向(telocate)--(这部分代码还没看懂-_-!!!),重定向完成之后会跳转到not_relocated标号处运行。

not_relocated:  mov     r0, #0     
1:              str     r0, [r2], #4            @ clear bss
                str     r0, [r2], #4
                str     r0, [r2], #4
                str     r0, [r2], #4
                cmp     r2, r3
                blo     1b
/*
 * The C runtime environment should now be setup sufficiently.
 * Set up some pointers, and start decompressing.
 *   r4  = kernel execution address
 *   r7  = architecture ID
 *   r8  = atags pointer
 */
                mov     r0, r4
                mov     r1, sp                  @ malloc space above stack
                add     r2, sp, #0x10000        @ 64k max
                mov     r3, r7
                bl      decompress_kernel
                bl      cache_clean_flush
                bl      cache_off
                mov     r0, #0                  @ must be zero
                mov     r1, r7                  @ restore architecture number
                mov     r2, r8                  @ restore atags pointer
 ARM(           mov     pc, r4  )               @ call kernel

重定向完成之后,首先清bss段,这时所有初始化C语言运行环境都要做的,然后调用decompress_kernel解压内核,之后跳转到非压缩内核启动阶段。

2.汇编阶段启动流程

对于tiny4412而言,内核的链接脚本为arch/arm/kernel/vmlinux.lds,它是由arch/arm/kernel/vmlinux.lds.S生成的。在链接脚本中,我们可以找到内核的入口

OUTPUT_ARCH(arm) 
ENTRY(stext)
jiffies = jiffies_64;
SECTIONS
{

可以看出内核的入口为stext,它在 linux/arch/arm/kernel/head.S 中被定义。

    .arm
    __HEAD
ENTRY(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:            )
  @设定为SVC模式,关闭IRQ、FIQ
    setmode    PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
                        @ and irqs disabled
    @检查CPU ID 是否匹配
    mrc    p15, 0, r9, c0, c0        @ get processor id 
    bl    __lookup_processor_type        @ r5=procinfo r9=cpuid
    movs    r10, r5                @ invalid processor (r5=0)?
 THUMB( it    eq )        @ force fixup-able long branch encoding
    beq    __error_p            @ yes, error p
#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
    adr    r3, 2f
    ldmia    r3, {r4, r8}
    sub    r4, r3, r4            @ (PHYS_OFFSET - PAGE_OFFSET)
    add    r8, r8, r4            @ PHYS_OFFSET
#else
    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传入的参数列表atags的合法性
    bl    __vet_atags
#ifdef CONFIG_SMP_ON_UP
    bl    __fixup_smp
#endif
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
    bl    __fixup_pv_table
#endif
  @创建初始页表
    bl    __create_page_tables
    /*
     * 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.
     */
    @建立C语言环境(代码重定位、清bss段)
    ldr    r13, =__mmap_switched        @ address to jump to after
                        @ mmu has been enabled
    adr    lr, BSYM(1f)            @ 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                )
 @开启MMU
1:    b    __enable_mmu
ENDPROC(stext)

__mmap_switched定义在arch/arm/kernel/head-common.S中

__mmap_switched:
        adr     r3, __mmap_switched_data
        ldmia   r3!, {r4, r5, r6, r7}
        cmp     r4, r5                          @ Copy data segment if needed
1:      cmpne   r5, r6
        ldrne   fp, [r4], #4
        strne   fp, [r5], #4
        bne     1b
        mov     fp, #0                          @ Clear BSS (and zero fp)
1:      cmp     r6, r7
        strcc   fp, [r6],#4
        bcc     1b
 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
汇编阶段代码主要完成了以下工作
①设置处理器为SVC模式并关闭中断
②调用__lookup_processor_type查找处理器信息结构体proc_info
③调用__enable_mmu打开MMU
④调用__create_page_tables创建初始页表
⑤调用__mmap_switched初始化C语言运行环境,最红跳转到C语言阶段入口函数start_kernel

3.C语言阶段启动流程

技术分享

内核启动流程,知识储备还不完善,以后更新 -_- ......
 
参考文章:
http://blog.csdn.net/zqixiao_09/article/details/50821995

 

Tiny4412 Linux 内核启动流程