linux 内核启动代码,Tiny4412 Linux 内核启动流程(示例代码)

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

linux 内核启动代码,Tiny4412 Linux 内核启动流程(示例代码)_第1张图片

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

.rept7

movr0, r0

.endr

ARM(movr0, 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: movr7, r1 @ save architecture IDmov r8, r2 @ save atags pointer

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

#ifndef __ARM_ARCH_2__

/*

* Booting from Angel - need toenter SVC mode anddisable

* FIQs/IRQs (numeric definitions from angel arm.h source).

* We only do this if we wereinuser mode on entry.

*/

@获取当前运行模式

mrs r2, cpsr @ get current mode

@测试是否为usr模式

tst r2, #3 @ notuser?

bne not_angelmovr0, #0x17 @ angel_SWIreason_EnterSVC

ARM( swi 0x123456 ) @ angel_SWI_ARM

THUMB( svc 0xab ) @ angel_SWI_THUMBnot_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 bssstr r0, [r2], #4

str r0, [r2], #4

str r0, [r2], #4

cmpr2, r3

blo 1b

/*

* The C runtime environment should now be setup sufficiently.

* Set up some pointers,andstart decompressing.

* r4 = kernel execution address

* r7 = architecture ID

* r8 = atags pointer

*/movr0, r4movr1, sp @ malloc space above stackadd r2, sp, #0x10000 @ 64kmaxmovr3, r7

bl decompress_kernel

bl cache_clean_flush

bl cache_offmov r0, #0@ must be zeromovr1, r7 @ restore architecture numbermovr2, 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 enteredinARM.

THUMB( bx r9 ) @ If this is a Thumb-2kernel,

THUMB( .thumb ) @ switch to Thumb now.

THUMB(1: )

@设定为SVC模式,关闭IRQ、FIQ

setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode

@andirqs disabled

@检查CPU ID 是否匹配

mrc p15,0, r9, c0, c0 @ get processor id

bl __lookup_processor_type @ r5=procinfo r9=cpuidmovs 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_MMFR0andr3, r3, #0xf @ extract VMSA supportcmp 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}subr4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET)addr8, r8, r4 @ PHYS_OFFSET

#else

ldr r8, =PHYS_OFFSET @ always constantinthis case

#endif

/*

* r1 = machine no, r2 = atagsordtb,

* 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 codeina 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,andr0 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) addressmovr8, r4 @ set TTBR1 to swapper_pg_dir

ARM(addpc, r10, #PROCINFO_INITFUNC )

THUMB(addr12, r10, #PROCINFO_INITFUNC )

THUMB(movpc, r12 )

@开启MMU1: 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}cmpr4, r5 @ Copy data segment if needed1: cmpne r5, r6

ldrne fp, [r4], #4strne fp, [r5], #4bne 1bmov fp, #0 @ Clear BSS (andzero fp)1: cmpr6, r7

strcc fp, [r6],#4bcc 1b

ARM( ldmia r3, {r4, r5, r6, r7, sp})

THUMB( ldmia r3, {r4, r5, r6, r7} )

THUMB( ldr sp, [r3, #16] )strr9, [r4] @ Save processor IDstrr1, [r5] @ Save machine typestrr2, [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语言阶段启动流程

linux 内核启动代码,Tiny4412 Linux 内核启动流程(示例代码)_第2张图片

内核启动流程,知识储备还不完善,以后更新 -_- ......

参考文章:

http://blog.csdn.net/zqixiao_09/article/details/50821995

你可能感兴趣的:(linux,内核启动代码)