Kernel启动和加载流程

ARM 199浏览

1、vmlinux.lds.S

链接脚本

OUTPUT_ARCH(arm)

ENTRY(stext) 定义编译内核为arm,程序入口为stext。连接脚本后面定义了SECTIONS

2、head.S

head.S主要做的事情是处理u-boot传入的参数,具体如下:判断是否支持这个CPU、判断是否支持这个单板(对比机器ID)、建立一级页表、使能MMU、跳到start_kernel函数

head.S在/arch/arm/kernel目录下,链接脚本中定义的入口函数就在这里定义:

ENTRY(stext)
setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
@ and irqs disabled
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid //判断cpu类型
movs r10, r5 @ invalid processor (r5=0)?
beq __error_p @ yes, error 'p'
bl __lookup_machine_type @ r5=machinfo//判断机器ID
movs r8, r5 @ invalid machine (r5=0)?
beq __error_a @ yes, error 'a'
bl __vet_atags
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_machine_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, __switch_data @ address to jump to after
@ mmu has been enabled
adr lr, BSYM(__enable_mmu) @ return (PIC) address
 ARM( add pc, r10, #PROCINFO_INITFUNC )
 THUMB( add r12, r10, #PROCINFO_INITFUNC )
 THUMB( mov pc, r12 )

ENDPROC(stext)

//使能MMU

/*
 * Setup common bits before finally enabling the MMU.  Essentially
 * this is just loading the page table pointer and domain access
 * registers.
 */
__enable_mmu:
#ifdef CONFIG_ALIGNMENT_TRAP
orr r0, r0, #CR_A
#else
bic r0, r0, #CR_A
#endif
#ifdef CONFIG_CPU_DCACHE_DISABLE
bic r0, r0, #CR_C
#endif
#ifdef CONFIG_CPU_BPREDICT_DISABLE
bic r0, r0, #CR_Z
#endif
#ifdef CONFIG_CPU_ICACHE_DISABLE
bic r0, r0, #CR_I
#endif
mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) |
      domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) |
      domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) |
      domain_val(DOMAIN_IO, DOMAIN_CLIENT))
mcr p15, 0, r5, c3, c0, 0 @ load domain access register
mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
b __turn_mmu_on

ENDPROC(__enable_mmu)

head-common.S中跳转kernel:

/*
 * 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 pointer
 *  r9  = processor ID
 */
__mmap_switched:
adr r3, __switch_data + 4

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

ENDPROC(__mmap_switched)

3、start_kernel

/init/main.c中定义了start_kernel函数,start_kernel是对操作系统的初始化,包括中断、串口、定时器、外设、操作系统的一些机制等。