微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM linux解析之压缩内核zImage的启动过程

ARM linux解析之压缩内核zImage的启动过程

时间:11-10 来源:互联网 点击:

大家千万不要纠结它,因为它是ARMv2架构以前的汇编方法,用于模式变换,和中断关闭的,看不明白也没关系,因为我们以后也用不到。这里知道一下有这个事就行了。

行,到这里.start段就完了,代码那么多,其实就是做一件事,保证运行下面的代码时已经进入了SVC模式,并保证中断是关的,完了.start部分结束。

3.。text段开始,先是内核解压地址的确定

再往下看,代码如下:

.text

#ifdefCONFIG_AUTO_ZRELADDR

@ determine final kernel image address

movr4, pc

and r4, r4, #0xf8

add r4, r4, #TEXT_OFFSET

#else

ldrr4, =zreladdr

#endif

额~~~~不要小这一段代码,东西好多啊。如哪入手呢?好吧,先从linux基本参数入手吧,见表.1,里面我写的很详细,因为表格我要放一页,解释我就写在上面了。TEXT_OFFSET是代码相对于物理内存的偏移,通常选为32k=0x8。这个是有原因的,具体的原因后面会说。先看CONFIG_AUTO_ZRELADDR这个宏所含的内容,它的意思是如果你不知道ZRELADDR地址要定在内存什么地方,那么这段代码就可以帮你。看到0xf8了吧,那么后面有多少个0呢?答案是27个,那么2的27次方就是128M,这就明白了,只要你把解压程序放在你最后解压完成后的内核空间的128M之内的偏移的话,就可以自动设定好解压后内核要运行的地址ZRELADDR。

如果你没有定义的话,那么,就会去取zreladdr作为最后解压的内核运行地。那么这个zreladdr是从哪里来的呢?答案是在:arch/arm/boot/compressed/Makefile中定义的

# Supply ZRELADDR to the decompressor via a linker symbol.

ifneq ($(CONFIG_AUTO_ZRELADDR),y)

LDFLAGS_vmlinux += --defsymzreladdr=$(ZRELADDR)

endif

ZRELADDR这又是哪里定义的呢?答案是在:arch/arm/boot/Makefile中定义的

ifneq ($(MACHINE),)

include $(srctree)/$(MACHINE)/Makefile.boot

endif

# Note: the following conditions must always be true:

#ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)

#PARAMS_PHYS must be within 4MB of ZRELADDR

#INITRD_PHYS must be in RAM

ZRELADDR:= $(zreladdr-y)

PARAMS_PHYS:= $(params_phys-y)

INITRD_PHYS:= $(initrd_phys-y)

而里面的几个参数是在每个arch/arm/Mach-xxx/ Makefile.boot里面定义的,内容如下:

zreladdr-y:= 0x28

params_phys-y:= 0x20100

initrd_phys-y:= 0x21

这下知道了,绕了一大圈,终于知道r4存的是什么了,就是最后内核解压的起址,也是最后解压后的内核的运行地址,记住,这个地址很重要。

解压内核参数

解压时symbol

解释

ZTEXTADDR

千成不要看成ZTE啊,呵,这里是zImage的运行的起始地址,当内核从nor flash中运行的时候很重要,如果在ram中运行,这个设为0

ZBSSADDR

这个地址也是一样的,这个是BSS的地址,如果在nor中运行解压的话,这个地址很重要。这个要放在RAM。

ZRELADDR

这个地址很重要,这个是解压后内核存放的地址,也是最后解压后内核的运行起址。

一般设为内存起址的32K之后,如ARM: 0x28

ZRELADDR = PHYS_OFFSET + TEXT_OFFSET

INITRD_PHYS

RAM disk的物理地址

INITRD_VIRT

RAM disk的虚拟地址

__virt_to_phys(INITRD_VIRT) = INITRD_PHYS

PARAMS_PHYS

内核参数的物理地址

内核参数

PHYS_OFFSET

实际RAM的物理地址

对于当前ARM来说,就是0x20

PAGE_OFFSET

内核空间的如始虚拟地址,通常: 0xC0,高端1G

__virt_to_phys(PAGE_OFFSET) = PHYS_OFFSET

TASK_SIZE

用户进程的内存的最太值(以字节为单位)

TEXTADDR

内核启运行的虚拟地址的起址,通常设为0xC8

TEXTADDR = PAGE_OFFSET + TEXT_OFFSET

__virt_to_phys(TEXTADDR) = ZRELADDR

TEXT_OFFSET

相对于内存起址的内核代码存放的偏移,通常设为32k (0x8)

DATAADDR

这个是内核数据段的虚拟地址的起址,当用zImage的时候不要定义。

表.1内核参数解释

4.打开ARM系统的cache,为加快内核解压做好准备

可以看到,打开cache的就一个函数,如下:

blcache_on

看起来很少,其实展开后内容还是很多的。我们来看看这个cache_on在哪里,可以找到代码如下:

.align5

cache_on:movr3, #8@ cache_on function

bcall_cache_fn

这里设计的很精妙的,只可意会,注意movr3, #8,不多解释,跟进去call_cache_fn:

call_cache_fn:adr r12,proc_types

#ifdefCONFIG_CPU_CP15

mrcp15, 0, r9, c0, c0@ get processor ID

#else

ldrr9, =CONFIG_PROCESSOR_ID

#endif

1:ldrr1, [r12, #0]@ get value

ldrr2, [r12, #4]@ get mask

eor r1, r1, r9@ (real ^ match)

tstr1, r2@& mask

ARM(addeqpc, r12,r3) @ call cache function

THUMB(addeqr12,

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top