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
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 )
: 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, # @ 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, #
: str r0, [r2], # @ clear bss
str r0, [r2], #
str r0, [r2], #
str r0, [r2], #
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, # @ 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- kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(: )
@设定为SVC模式,关闭IRQ、FIQ
setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
@ and irqs disabled
@检查CPU ID 是否匹配
mrc p15, , r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=)?
THUMB( it eq ) @ force fixup-able long branch encoding
beq __error_p @ yes, error 'p'
#ifdef CONFIG_ARM_LPAE
mrc p15, , r3, c0, c1, @ read ID_MMFR0
and r3, r3, #0xf @ extract VMSA support
cmp r3, # @ 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
: 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
: cmpne r5, r6
ldrne fp, [r4], #
strne fp, [r5], #
bne 1b
mov fp, # @ Clear BSS (and zero fp)
: cmp r6, r7
strcc fp, [r6],#
bcc 1b
ARM( ldmia r3, {r4, r5, r6, r7, sp})
THUMB( ldmia r3, {r4, r5, r6, r7} )
THUMB( ldr sp, [r3, #] )
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 内核启动流程的更多相关文章

  1. linux 内核启动流程

    Linux内核启动流程详细分析: http://www.linuxidc.com/Linux/2014-10/108034.htm ARM Linux内核启动过程: http://blog.csdn. ...

  2. 【内核】linux内核启动流程详细分析

    Linux内核启动流程 arch/arm/kernel/head-armv.S 该文件是内核最先执行的一个文件,包括内核入口ENTRY(stext)到start_kernel间的初始化代码, 主要作用 ...

  3. 【内核】linux内核启动流程详细分析【转】

    转自:http://www.cnblogs.com/lcw/p/3337937.html Linux内核启动流程 arch/arm/kernel/head-armv.S 该文件是内核最先执行的一个文件 ...

  4. linux 内核启动流程分析,移植

    分析 linux-2.6.22.6 内核启动流程 移植 linux-3.4.2 到 JZ2440 开发板 Linux内核源码百度云链接: https://pan.baidu.com/s/1m1ymGl ...

  5. Linux内核启动流程与模块机制

    本文旨在简单的介绍一下Linux的启动流程与模块机制: Linux启动的C入口位于/Linux.2.6.22.6/init/main.c::start_kernel() 下图简要的描述了一下内核初始化 ...

  6. Linux内核启动流程(简介)

    1. vmlinux.lds 首先分析 Linux 内核的连接脚本文件 arch/arm/kernel/vmlinux.lds,通过链接脚本可以找到 Linux 内核的第一行程序是从哪里执行的: 第 ...

  7. Linux内核启动流程分析(一)【转】

    转自:http://blog.chinaunix.net/uid-25909619-id-3380535.html 很久以前分析的,一直在电脑的一个角落,今天发现贴出来和大家分享下.由于是word直接 ...

  8. linux内核启动流程[转]

    启动流程一览 既然启动是很严肃的一件事,那我们就来了解一下整个启动的过程吧! 好让大家比较容易发现启动过程里面可能会发生问题的地方,以及出现问题后的解决之道! 不过,由於启动的过程中,那个启动管理程序 ...

  9. Linux内核启动流程分析(二)【转】

    转自:http://blog.chinaunix.net/uid-25909619-id-3380544.html S3C2410 Linux 2.6.35.7启动分析(第二阶段) 接着上面的分析,第 ...

随机推荐

  1. SPOJ375 QTREE - Query on a tree

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  2. Codeforces Round #373 (Div. 2) E. Sasha and Array 矩阵快速幂+线段树

    E. Sasha and Array time limit per test 5 seconds memory limit per test 256 megabytes input standard ...

  3. flsk-SQLALchemy

    SQLALchemy 一.介绍     SQLALchemy是一个基于Python实现的ORM框架.该框架是建立在DB API之上,使用关系对象映射进行数据库操作     简言之便就是:将类和对象转换 ...

  4. spring boot: spring Aware的目的是为了让Bean获得Spring容器的服务

    Spring Aware的目的是为了让Bean获得Spring容器的服务 //获取容器中的bean名称import org.springframework.beans.factory.BeanName ...

  5. UML用例建模解析(二)---------用例执行者之间关系

    (1) 关联关系 关联关系是指执行者与用例之间的关系,又称为通信关系,如果某个执行者可以对某个用例进行操作,它们之间就具有关联关系,如下图所示,“经理”有一个功能为“查看库存报表”,因此可以在执行者“ ...

  6. 用find命令查找最近修改过的文件

    Linux的终端上,没有windows的搜索那样好用的图形界面工具,但find命令确是很强大的. 比如按名字查找一个文件,可以用 find / -name targetfilename . 唉,如果只 ...

  7. asp.net 基础知识

    1. DropDownList 的赋值 Response.Write(DropDownList1.Items.FindByText("潍坊").Value); Response.W ...

  8. 分享知识-快乐自己:HttpClient 访问 WebService 开放接口

    HttpClient: 场景需求如下: 1.项目中需要与一个基于HTTP协议的第三方的接口进行对接 2.项目中需要动态的调用WebService服务(不生成本地源码) 3.项目中需要利用其它网站的相关 ...

  9. LVM MBR分区(装载)

    必须有至少一个主分区(P),主分区个数+扩展分区个数<= 4个. 创建完主分区,可以创建扩展分区(E),扩展分区可以有1个,或者没有(扩展分区). 主分区(Primary  Partion)可以 ...

  10. webservice 传输数据过大,解析失败

    ERROR 错误信息: 已超过传入消息(65536)的最大消息大小配额.若要增加配额,请使用相应绑定元素上的 MaxReceivedMessageSize 属性. 错误场景: webservice 服 ...