Chinaunix首页 | 论坛 | 博客
  • 博客访问: 178919
  • 博文数量: 42
  • 博客积分: 2185
  • 博客等级: 大尉
  • 技术积分: 455
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-11 21:32
文章分类

全部博文(42)

文章存档

2012年(5)

2011年(13)

2010年(6)

2009年(18)

我的朋友

分类: LINUX

2009-11-25 20:08:36

      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) |
给主人留下些什么吧!~~