ARM linux解析之压缩内核zImage的启动过程
大家千万不要纠结它,因为它是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,
ARMlinux解析压缩内核zImage启动过 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)