MPC85xx (including BookE PPC) kernel early startup (old cuImage)
arch/powerpc/boot/zImage.ld.S =>
ENTRY(_zimage_start)
EXTERN(_zimage_start)
SECTIONS
{
_start = .;
=> next = _zimage_start => arch/powerpc/boot/crt0.S:_zimage_start()
这个函数在做了一些重定位的工作/cache flush之后最终:
/* Call platform_init() */
bl platform_init
/* Call start */
b start
以e500为例, platform_init()在arch/powerpc/boot/cuboot-85xx.c中,主要做一些初始化fdt(flat
device tree)的工作,fdt由dtc(device tree
compiler将arch/powerpc/boot/dts/mpc85xx.dts编译而来,编译之后生成的fdt被加到了zImage之前,见zImage.ld.S文件:
...
. = ALIGN(8);
_dtb_start = .;
.kernel:dtb : { *(.kernel:dtb) }
_dtb_end = .;
. = ALIGN(4096);
_vmlinux_start = .;
.kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
_vmlinux_end = .;
. = ALIGN(4096);
_initrd_start = .;
.kernel:initrd : { *(.kernel:initrd) }
_initrd_end = .;
...
platform_init完成后,fdt已经被正确加载,最后执行start()函数,这个函数位于arch/power/boot/main.c。
忽略细节的话这个函数最终将试图从zImage解压出来的vmlinux中获取vmlinux.start,这个start就是vmlinux(也就是内核真正开始的位置),参考Documentation/powerpc/booting-without-of.txt,当使用flat
device tree时:
r3 : physical pointer to the device-tree block
(defined in chapter II) in RAM
r4 : physical pointer to the kernel itself. This is
used by the assembly code to properly disable the MMU
in case you are entering the kernel with MMU enabled
and a non-1:1 mapping.
r5 : NULL (as to differentiate with method a)
arch/powerpc/boot/main.c:
...
kentry = (kernel_entry_t) vmlinux.addr;
if (ft_addr)
kentry(ft_addr, 0, NULL);
...
注意这里的kentry指向了从zImage解压后真正的vmlinux开始的位置,也就是arch/powerc/kernel/head_fsl_booke.S的_stext
(_start)函数。
/* As with the other PowerPC ports, it is expected that when code
* execution begins here, the following registers contain valid, yet
* optional, information:
*
* r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
* r4 - Starting address of the init RAM disk
* r5 - Ending address of the init RAM disk
* r6 - Start of kernel command line string (e.g. "mem=128")
* r7 - End of kernel command line string
*
*/
.section .text.head, "ax"
_ENTRY(_stext);
_ENTRY(_start);
注意上面的注释实际上是错的(请参考booting-without-of的那一段)。.section
.text.head将这段代码加入了.text.head代码段,看看vmlinux.ld.S:
...
ENTRY(_stext) /* 这个再次确定了vmlinux是从_stext开始的 */
...
/* Text and gots */
.text : AT(ADDR(.text) - LOAD_OFFSET) {
ALIGN_FUNCTION();
*(.text.head)
_text = .;
...
以上的脚本说明.text.head被放到了.text段的最开始的位置,由此可见.text字段的开始即是函数_stext(亦_start)。
后面就比较容易懂了,需要注意的是由于e500没有“实”模式,所以开始有很大一部分代码内核试图自己给自己做了一个tlb
映射(256M,通过IPROT保护并设置了PAGE_GUARD,确保TLB不会被tlbivax flush或是默认的TLB
LRU替换掉,如果结合arch/powerpc/kernel/head_44x.S看,会发现44x会保留TLB_index_63不被交换,注意44x只有64个TLB
entry),否则在异常向量未初始化完成的时候,有iTLB/dTLB miss,这件导致ISI/DSI异常,而这时候的异常向量还没有好..
阅读(1785) | 评论(0) | 转发(0) |