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
阅读(1067) | 评论(0) | 转发(0) |