ARM linux kernel启动流程 head.S(一)

2023-11-01 197浏览
百检网是一家专业的第三方检测平台,汇聚众多拥有权威资质的第三方检测机构为你提供一站式的检测服务,做检测就上百检网。百检网让检测从此检测,一份报告全国通用,专业值得信赖。
1. kernel运行的史前时期和内存布局在arm平台下,zImage.bin压缩镜像是由bootloader加载到物理内存,然后跳到zImage.bin里一段程序,它专门于将被压缩的kernel解压缩到KERNEL_RAM_PADDR开始的一段内存中,接着跳进真正的kernel去执行。该kernel的执行起点是stext函数,定义于arch/arm/kernel/head.S。

在分析stext函数前,先介绍此时内存的布局如下图所示

在开发板tqs3c2440中,SDRAM连接到内存控制器的Bank6中,它的开始内存地址是0x30000000,大小为64M,即0x20000000。 ARM Linux kernel将SDRAM的开始地址定义为PHYS_OFFSET。经bootloader加载kernel并由自解压部分代码运行后,*终kernel被放置到KERNEL_RAM_PADDR(=PHYS_OFFSET + TEXT_OFFSET,即0x30008000)地址上的一段内存,经此放置后,kernel代码以后均不会被移动。

在进入kernel代码前,即bootloader和自解压缩阶段,ARM未开启MMU功能。因此kernel启动代码一个重要功能是设置好相应的页表,并开启MMU功能。为了支持MMU功能,kernel镜像中的所有符号,包括代码段和数据段的符号,在链接时都生成了它在开启MMU时,所在物理内存地址映射到的虚拟内存地址。

以arm kernel**个符号(函数)stext为例,在编译链接,它生成的虚拟地址是0xc0008000,而放置它的物理地址为0x30008000(还记得这是PHYS_OFFSET+TEXT_OFFSET吗?)。实际上这个变换可以利用简单的公式进行表示:va = pa – PHYS_OFFSET + PAGE_OFFSET。Arm linux*终的kernel空间的页表,就是按照这个关系来建立。

之所以较早提及arm linux 的内存映射,原因是在进入kernel代码,里面所有符号地址值为清一色的0xCXXXXXXX地址,而此时ARM未开启MMU功能,故在执行stext函数**条执行时,它的PC值就是stext所在的内存地址(即物理地址,0x30008000)。因此,下面有些代码,需要使用地址无关技术。

2. 一览stext函数

这里的启动流程指的是解压后kernel开始执行的一部分代码,这部分代码和ARM体系结构是紧密联系在一起的,所以*好是将ARM ARCHITECTURE REFERENCE MANUL仔细读读,尤其里面关于控制寄存器啊,MMU方面的内容~

stext函数定义在Arch/arm/kernel/head.S,它的功能是获取处理器类型和机器类型信息,并创建临时的页表,然后开启MMU功能,并跳进**个C语言函数start_kernel。

stext函数的在前置条件是:MMU, D-cache, 关闭; r0 = 0, r1 = machine nr, r2 = atags prointer.

前面说过解压以后,代码会跳到解压完成以后的vmlinux开始执行,具体从什么地方开始执行我们可以看看生成的vmlinux.lds(arch/arm/kernel/)这个文件:

1.OUTPUT_ARCH(arm)

2.ENTRY(stext)

3.jiffies=jiffies_64;

4.SECTIONS

5.{

6..=0x80000000+0x00008000;

7..text.head:{

8._stext=.;

9._sinittext=.;

0.*(.text.h

很明显我们的vmlinx*开头的section是.text.head,这里我们不能看ENTRY的内容,以为这时候我们没有操作系统,根本不知道如何来解析这里的入口地址,我们只能来分析他的section(不过一般来说这里的ENTRY和我们从seciton分析的结果是一样的),这里的.text.head section我们很容易就能在arch/arm/kernel/head.S里面找到,而且它里面的**个符号就是我们的stext:

#.section".text.head","ax"

#

#ENTRY(stext)

#

#/*设置CPU运行模式为SVC,并关中断*/

#

#msrcpsr_c,#PSR_F_BIT|PSR_I_BIT|SVC_MODE@ensuresvcmode

#

#@andirqsdisabled

#

#mrcp15,0,r9,c0,c0@getprocessorid

#

#bl__lookup_processor_type@r5=procinfor9=cupid

#

#/*r10指向cpu对应的proc_info记录*/

#

#movsr10,r5@invalidprocessor(r5=0)?

#

#beq__error_p@yes,error'p'

#

#bl__lookup_machine_type@r5=machinfo

#

#/*r8指向开发板对应的arch_info记录*/

#

#movsr8,r5@invalidmachine(r5=0)?

#

#beq__error_a@yes,error'a'

#

#/*__vet_atags函数涉及bootloader造知kernel物理内存的情况,我们暂时不分析它。*/

#

#bl__vet_atags

#

#/*创建临时页表*/

#

#bl__create_page_tables

#/*

#

#*ThefollowingcallsCPUspecificcodeinapositionindependent

#

#*manner.Seearch/arm/mm/proc-*.Sfordetails.r10=baseof

#

#*xxx_proc_infostructureselectedby__lookup_machine_type

#

#*above.Onreturn,theCPUwillbereadyfortheMMUtobe

#

#*turnedon,andr0willholdtheCPUcontrolregistervalue.

#

#*/

#

#/*这里的逻辑关系相当复杂,先是从proc_info结构中的中跳进__arm920_setup函数,

#

#*然后执__enable_mmu函数。*后在__enable_mmu函数通过movpc,r13来执行__switch_data,

#

#*__switch_data函数在*后一条语句,鱼跃龙门,跳进**个C语言函数start_kernel。

#*/

#

#ldrr13,__switch_data@addresstojumptoafter

#

#@mmuhasbeenenabled

#

#adrlr,__enable_mmu@return(PIC)address

#

#addpc,r10,#PROCINFO_INITFUNC

#

#ENDPROC(stext)

这里的ENTRY这个宏实际我们可以在include/linux/linkage.h里面找到,可以看到他实际上就是声明一个GLOBAL Symbol,后面的ENDPROC和END**的区别是前面的声明了一个函数,可以在c里面被调用。

1.#ifndefENTRY

2.#defineENTRY(name)/

3..globlname;/

4.ALIGN;/

5.name:

6.#endif

7.#ifndefWEAK

8.#defineWEAK(name)/

9..weakname;/

10.name:

11.#endif

12.#ifndefEND

13.#defineEND(name)/

14..sizename,.-name

15.#endif

16./*Ifsymbol'name'istreatedasasubroutine(getscalled,andreturns)

17.*thenpleaseuseENDPROCtomark'name'asSTT_FUNCforthebenefitof

18.*staticanalysistoolssuchasstackdepthanalyzer.

19.*/

20.#ifndefENDPROC

21.#defineENDPROC(name)/

22..typename,@function;/

23.END(name)

24.#endif

找到了vmlinux的起始代码我们就来进行分析了,先总体概括一下这部分代码所完成的功能,head.S会**检查proc和arch以及atag的有效性,然后会建立初始化页表,并进行CPU必要的处理以后打开MMU,并跳转到start_kernel这个symbol开始执行后面的C代码。这里有很多变量都是我们进行kernel移植时需要特别注意的,下面会一一讲到。

在这里我们**看看这段汇编开始跑的时候的寄存器信息,这里的寄存器内容实际上是同bootloader跳转到解压代码是一样的,就是r1=arch r2=atag addr。下面我们就具体来看看这个head.S跑的过程:

1.msrcpsr_c,#PSR_F_BIT|PSR_I_BIT|SVC_MODE@ensuresvcmode


百检网秉承“客户至上,服务为先,精诚合作,以人为本”的经营理念,始终站在用户的角度解决问题,为客户提供“一站购物式”的新奇检测体验,打开网站,像挑选商品一样简单,方便。打破行业信息壁垒,建构消费和检测机构之间高效的沟通平台