ARM linux解析之压缩内核zImage的启动过程
(0x24)存入CP15的C2寄存器,这样ARM就知道到哪里去找那些页表项了。下面我们来看一下整个MMU的虚拟地址的寻址过程,如图4所示。
简单解释一下。首先,ARM的CPU从CP15的C2寄存器中找取出页表基地址,然后把虚拟地址的最高12位左移两位变为14位放到页表基址的低14位,组合成对应1M空间的页表项在MMU页表中的地址。然后,再取出页表项的值,检查AP位,域,判断是否有读写的权限,如果没有权限测会抛出数据或指令异常,如果有权限,就把最高12位取出加上虚拟地址的低20位段内偏移地址组合成最终的物理地址。到这里整个MMU从虚拟地址到物理地址的转换过程就完成了。
这段代码里,只会开启页表所在代码的开始的256K对齐的一个0x10(256M)空间的大小(这个空间必然包含解压后的内核),使能cache和write buffer,其他的4G-256M的空间不开启。这里使用的是1:1的映射。到这里也很容易明白MMU和cache和write buffer的关系了,为什么不开MMU无法使用cache了。
图.4 MMU的段页表的虚拟地址与物理地址的转换过程
这里的4G空间全部映射完成之后,还会做一个映射,代码如下:
movr1, #0x1e
orr r1, r1, #3 < 10
movr2, pc
movr2, r2, lsr #20
orr r1, r1, r2, lsl #20
add r0, r3, r2, lsl #2
strr1, [r0], #4
add r1, r1, #1048576
strr1, [r0]
movpc, lr
通过注释就可以知道把当前PC所在地址1M对齐的地方的2M空间开启cache和write buffer为了加快代码在nor flash中运行的速度。然后反回,到这里16K的MMU页表就完全建立好了。
然后再反回到建立页表后的代码,如下:
movr0, #0
mcrp15, 0, r0, c7, c10, 4@ drain write buffer
tstr11, #0xf@ VMSA
mcrnep15, 0, r0, c8, c7, 0@ flush I,D TLBs
#endif
mrcp15, 0, r0, c1, c0, 0@ read control reg
bicr0, r0, #1 < 28@ clear SCTLR.TRE
orr r0, r0, #0x5@ I-cache enable, RR cache replacement
orr r0, r0, #0x003c@ write buffer
#ifdef CONFIG_MMU
#ifdef CONFIG_CPU_ENDIAN_BE8
orr r0, r0, #1 < 25@ big-endian page tables
#endif
orrner0, r0, #1@ MMU enabled
movner1, #-1
mcrnep15, 0, r3, c2, c0, 0@ load page table pointer
mcrnep15, 0, r1, c3, c0, 0@ load domain access control
#endif
mcrp15, 0, r0, c1, c0, 0@ load control register
mrcp15, 0, r0, c1, c0, 0@ and read it back
movr0, #0
mcrp15, 0, r0, c7, c5, 4@ ISB
movpc, r12
这段代码就不具体解释了,多数是关于CP15的控制寄存器的操作,主要是flush I-cache,D-cache, TLBS,write buffer,然后存页表基址啊,最后打开MMU这个是最后一步,前面所有东西都设好之后再使用MMU,否则系统就会挂掉。最后用保存在r12中的地址,反回到BL cache_on的下一句代码。如下:
restart:adr r0,LC0
ldmiar0, {r1, r2, r3, r6, r10, r11, r12}
ldrsp, [r0, #28]
sub r0, r0, r1@ calculate the delta offset
add r6, r6, r0@ _edata
add r10, r10, r0@ inflated kernel size location
好了,先来看一下LC0是什么东西吧。
.align2
.typeLC0, #object
LC0:.wordLC0@ r1
.word__bss_start@ r2
.word_end@ r3
.word_edata@ r6
.wordinput_data_end - 4 @ r10 (inflated size location)
.word_got_start@ r11
.word_got_end@ ip
.word.L_user_stack_end@ sp
.sizeLC0, . - LC0
好吧,要理解它,再把arch/arm/boot/vmlinux.lds.in搬出来吧:
_got_start = .;
.got: { *(.got) }
_got_end = .;
.got.plt: { *(.got.plt) }
_edata = .;
. = BSS_START;
__bss_start = .;
.bss: { *(.bss) }
_end = .;
. = ALIGN(8);
.stack: { *(.stack) }
.align
.section ".stack", "aw", %nobits
再加上最后一段代码,关于stack的空间的大小分配:
.L_user_stack:.space4096
.L_user_stack_end:
这里不仅可以看到各个寄存器里所存的值的意思,还可以看到. = BSS_START;在这里的作用
arch/arm/boot/compressed/Makefile里面:
ifeq ($(CONFIG_ZBOOT_ROM),y)
ZTEXTADDR:= $(CONFIG_ZBOOT_ROM_TEXT)
ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS)
else
ZTEXTADDR:= 0
ZBSSADDR := ALIGN(8)
endif
SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
对应到这里的话,就是BSS_START =ALIGN(8),这个替换过程会在vmlinux.lds.in到vmlinux.lds的过程中完成,这个过程主要是为了有些内核在nor flash中运行而设置的。
好了,再次言归正传,从vmlinux.lds文件,可以看到链接后各个段的位置,如下。
图.5 zImage各个段的位置
从这里可以看到,zImage在RAM中运行和在NorFlash中直接运行是有些
ARMlinux解析压缩内核zImage启动过 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)