Chinaunix首页 | 论坛 | 博客
  • 博客访问: 461256
  • 博文数量: 107
  • 博客积分: 6073
  • 博客等级: 准将
  • 技术积分: 790
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-14 15:34
文章分类

全部博文(107)

文章存档

2010年(1)

2009年(106)

分类: 嵌入式

2009-08-18 10:01:01

作者:wangxinus,
来源:
http://wangxinus.cublog.cn
说明:转载请注明来源,交流请Email给作者

Renesas提供的rsk+7203的BSP包,完全编译完成以后,有交叉编译工具链 sh-linux-,位于  build/target/ 目录下:
sh-linux-addr2line  sh-linux-gcc        sh-linux-objcopy
sh-linux-ar         sh-linux-gcc-3.4.6  sh-linux-objdump
sh-linux-as         sh-linux-gccbug     sh-linux-ranlib
sh-linux-c++filt    sh-linux-gcov       sh-linux-readelf
sh-linux-cpp        sh-linux-ld         sh-linux-size
sh-linux-elf2flt    sh-linux-ld.real    sh-linux-strings
sh-linux-flthdr     sh-linux-nm         sh-linux-strip

包含启动代码的linux镜像和NOR Flash 上面使用的 jffs2 文件系统镜像,位于 build/sh7203-images/ 目录下:
drwxrwxrwx 1 root root    4096 2009-08-17 16:21 root_fs
-rwxrwxrwx 1 root root 2097152 2009-08-17 16:21 sh7203-filesystem.bin
-rwxrwxrwx 1 root root 1552388 2009-08-17 09:37 sh7203-linux.abs.bin

rsk+7203提供的BSP中,Linux的引导并没有移植常见的bootloader,比如Uboot。笔者也尝试移植了最新版的Uboot到rsk+7203的开发板,通过交叉编译,是完全能够在上面运行的,下载功能等还没有做相应的测试,这里暂且不谈。上面说到,linux系统镜像包含了启动代码,这部分启动代码是Renesas人自己写的。我也相信,对高手而言,写一个芯片的启动代码应该不是难事,但对我们初学着,一步一步分析,按图索骥,才能渐渐接近事物的本质。

我们编译内核,并最终下到开发板中的linux内核镜像,一般是zImage。而我们编译BSP的到的镜像是sh7203-linux.abs.bin,而它其中已经包含了引导代码,那么,肯定在zImage上作了文章, 把引导代码和linux的压缩镜像重新连接,得到了sh7203-linux.abs.bin。

引导代码包含在 bootstrap目录下面。以下是 bootstrap/makefile 中的片段:

build: sh7203-linux.abs symbols sh7203-linux.abs.bin
    @echo "Build complete"
    @echo "sh7203-linux.abs.bin is the binary image to write to flash."
build应该是一个伪目标,便于我们同时生成几个目标,其中便有我们最感兴趣的sh7203-linux.abs.bin。

%.bin:
    @echo "Converting $* to $@"
    @sh-linux-objcopy $* -O binary $@
看来sh7203-linux.abs.bin是sh7203-linux.abs转换为2进制格式而来。

sh7203-linux.abs: sh7203-linux.abs.pre
    mv sh7203-linux.abs.pre sh7203-linux.abs
而sh7203-linux.abs其实是sh7203-linux.abs.pre的重命名的结果。

# .pre allows you to type make sh7263-linux.abs.pre to remake without disturbing a current JTAG operation.
sh7203-linux.abs.pre: $(SRCS) zImage startup.lds zImage FORCE
    $(CC) $(CFLAGS) -c $(SRCS)
#    $(LD) *.o -o first -e initialise -EB --section-start VECTTBL=0 -Ttext 0x1000
#    $(LD) *.o -o startup -EB -T startup.lds
    $(LD) -r --format binary \
        --oformat elf32-sh-linux \
        -EB \
        -T zImage.scr \
        zImage \
        -o zImage.o
    $(LD) *.o -o $@ -EB -T startup.lds
果然,和我们的猜测是一样的。这里把引导代码和zImage重新连接。我想,关注的重点应该是startup.lds,该连接脚本中应该记录了连接的信息。

startup.lds: startup.lds.S
    $(CC) -traditional -E -C -P -I. startup.lds.S >startup.lds
startup.lds来源于startup.lds.S,比如处理了预处理语句等等。我们现来看看实际用到的startup.lds中的信息,再去看看startup.lds.S中为我们提供的其他选项。

MEMORY
{
 /* ROM (rx):   ORIGIN = 0x00000000, LENGTH =  4194304  /* 4 MB's  / 32 Mbits */
    ROMBT (rx):    ORIGIN = 0x00000000, LENGTH =  262144/* 0x40000 : Kernel Offset */
    ROMKN (rx):    ORIGIN = 0x00040000, LENGTH = 1835008/* 2 MB's-Boot Code:The Kernel */
    ROMFL (rx):    ORIGIN = 0x00200000, LENGTH = 2097152/* 2 MB's */
    RAM (rw):   ORIGIN = 0x0C000000, LENGTH = 16777216  /* 16 MB's / 128 Mbits */
    OCRAM (rw): ORIGIN = 0xFFF80000, LENGTH =    16384
    STACK (rw): ORIGIN = 0xFFFBFC00, LENGTH =     1536
}

ENTRY(initialise)
rsk+7203上电复位以后,根绝绝对地址0x00000000开始的向量表中, 定义在vect.c中,复位的pc地址,这里就是函数initialise的地址,开始运行,启动引导代码。内核的镜像被写入到0x00040000开始的位置,文件系统写入0x00200000开始的位置,引导代码和内核镜像一共用了2M,文件系统用掉了余下的2M Nor Flash 空间。

从电路图上得知,事实上SDRAM一共级联了2片,都是16bit的,每片128Mbit。rsk+7203默认的SDRAM的总线模式是16bit的,所以我们只能寻址到其中的一片, 后面我们运行中,查看内存只有16M's就是这个原因。

/* 开发板的终端运行 */
cat /proc/meminfo
如果我们把SDRAM设置为32bit总线模式,那么我们就可以寻址2片SDRAM, 内存将被扩展到32M's, 这里的修改涉及到硬件和软件,暂时不提。

指定的入口函数是 initialise, 这个函数位于  bootstrap/init.c :59。

void initialise(void)
{
    void (*linuxstartup)(); // 这里定义了一个函数指针, 当所有的初始化工作完成以后, 指向linux内核的绝对地址, 启动linux
    /* Set up the hardware    */ // 初始化硬件,
    HardwareSetup();
    /* initsct!! */
    InitialiseDisplay(); /* Setup debug LCD */ //初始化测试用LCD屏,是小的黑白屏, 我们没有使用。。。
    DisplayString(LCD_LINE1," SH7203 "); //在 测试屏上输出信息。
    DisplayString(LCD_LINE2," WOW! ");
    SCIF_Init(); //初始化带FIFO的串行通信接口 SCIF
    LED1 = LED_ON; //完成以后点亮 LED1
    MemoryTest(); //内存测试, 向指定的内存写入数据, 然后再读出, 判断是否数据被正常写入。
    LED2 = LED_ON;//完成以后点亮 LED2
    linuxstartup = 0x40000; //这里很重要,把定义的函数指针指向0x40000的绝对地址,startup.lds中分析得到,这个地址就是linux内核镜像的起始地址,

                            //然后我们就可以通过调用函数的形式,跳转到0x40000处开始执行, 解压zImage,并启动linux内核。不过,这里的作用还只是

                            //测试内核的镜像是否存在。


    /* Test to check flash has been written */ // flash被擦除时,全置为0xFF, 通过判断内核镜像处的数据是否是0xFFFFFFFF, 可以得知有没有数据写入。

    if ( * (void **)linuxstartup == 0xFFFFFFFF )
        panic ("\r\nNo Kernel Found ... Please Flash with the E10A Jtag Debugger\r\n"); //死机

    qvga_initialise(); // 初始化那快漂亮的QVGA屏,这让我有向上面移植电影播放器或者小游戏的冲动。。。。

    load_splash(0);

    /* text_write 是向串口输入一些信息。 后面的都是输入启动的信息。 */
#ifdef USE_32BIT_SDRAM_INTERFACE
    text_write("\r\nBooting with 32 Bit SDRAM Interface\r\n");
#else
    text_write("\r\nBooting with 16 Bit SDRAM Interface\r\n");
#endif

    text_write ("Bootload Complete\r\n");
    text_write ("Bootloader compiled at : " __DATE__ "\r\n");
    //#include "date.text"

    text_write ("Starting linux Decompressor\r\n");

    linuxstartup = 0x40000; //和我上面提到的一样,不过这次是真格的了, HOHO~ 它又测试了一遍。。。 不过最终它启动了内核
    
    /* Test to check flash has been written */
    if ( * (void **)linuxstartup == 0xFFFFFFFF )
        panic ("\r\nNo Kernel Found ... Please Flash with the E10A Jtag Debugger\r\n");

    LED3 = LED_ON; //如果没有问题, 点亮LED3
//    startup();    /* Call the zImage startup and decompressor */

    linuxstartup();    /* Call the zImage startup and decompressor */ //执行0x40000处代码, zImage起始处, 解压内核,然后启动, 剩下的事情就交给linux了。

    /* We should never get here, and we should never leave here if we do! */
    panic("Linux Startup Returned or Failed\n"); //执行到这里,说明0x40000处执行的代码错误了, 正常的启动是不会到这里来的。。。
}


总结:
    在本文中,笔者对rsk+7203开发板上linux的启动过程进行了简单的分析, 所有的启动过程和任何的开发启动的原理都是类似的。
    我是站在一个完全的初学者的角度,逐步分析,找到问题的关键所在, 由于Renesas提供的资料相当有限,网上的资料更是微乎其微,
    笔者作为一个初学者, 走了不少弯路,也犯了不少错误。文中的不足之处,欢迎批评。 Email:wangxinus@gmail.com


阅读(969) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~