OMAP3530的启动程序——OclO开发笔记
Rev 1.80
1 OclO概述
OclO是基于TI发布的EVM3530开发板的03.00.01.06版本的PSP包中的x-loader修改而成的。x-loader是基于u-boot精简而成的,OMAP3530内部只有64KB的SRAM,不能存下整个u-boot,因此才会先启动x-loader,把外部的RAM初始化好,再把u-boot从Nand、OneNand或SD卡中读出来运行,这样,相当于启动过程分为3级:1、ROM Code;2、一级启动代码x-loader;3、二级启动代码u-boot。但是,原版的x-loader只实现了加载u-boot这一功能。实际上,x-loader是一个很好的模板,很容易增加其他功能,OclO就是这样诞生的,并且希望能保持x-loader的简洁程度。
1.1 关于OclO名字的由来
OclO的意思是“Octagram的loader”,其中Octagram就是我的英文名。
1.2 OclO的版本号
OclO的版本号分为主版本号和次版本号,例如1.80。每个主版本号中预计要实现哪些功能可以从下面的粗斜体字部分查到,而次版本号表示这些计划的完成进度,“1.80”表示版本1的所有预计功能完成了80%。
目前版本号:1.80
版本1要完成的功能:
(1)增加一个启动菜单。
(2)OclO运行时先倒计时,采用串口作为终端设备,在倒计时中如果按下任意键,则进入启动菜单;如果没有任何输入,则自动加载按以下顺序搜索并加载u-boot:SD卡 > Nand Flash。
(3)在启动菜单中增加功能[B],启动u-boot.bin。
(4)在启动菜单中增加功能[O],加载用户自定义的程序,这样,OMAP3530就可以当成单片机来玩了。
(5)在启动菜单中增加功能[D],将OMAP3530配置成一个DSP,这样就可以在CCS下进行DSP实验了,和真的DSP没有什么区别。
2 OclO使用说明
(1)将编译产生的文件MLO放入SD卡的fat32主分区,或存入Nand Flash的x-loader分区,并设置好OMAP3530的启动引脚。
(2)OclO启动时,会倒计时,在倒计时结束前,按下A~Z、0~9、标点等的任意键可进入启动菜单;否则将自动启动u-boot。
(3)启动菜单中,输入B或b将启动u-boot。
(4)启动菜单中,输入O或o将加载自定义的程序,加载地址0x80008000。
(5)启动菜单中,输入D或d将进入DSP模式(此功能还未完成)。
3 OclO编译说明
(1)在终端中将路径切换到OclO的目录下,例如:
cd /home/octagram/workspace/ARM/OMAP3530/OclO(2)配置:
make Ocsom3530_config
(3)使用下面命令可以开始编译,编译结束后将产生一个文件MLO,这个是OclO.bin文件加上信息头后的产生的文件:
make
(4)若要删除编译产生的文件:
make clean
(5)如果要将产生的文件、配置信息等全部删除(压缩备份前使用):
make distclean
4 OclO目录说明
OclO是由u-boot的修改而来的,所以大部分文件夹或文件功能是相同的,打开OclO的目录,可以看到以下文件夹(蓝)和文件(黑):
★ board:和具体板子有关的源代码;
★ cpu:和cpu有关的源代码;
★ disk:和磁盘分区有关的源代码;
★ doc:文档;
★ drivers:驱动;
★ fs:文件系统;
★ include:头文件;
★ lib:一些库函数,包括“除以0”错误处理、printf函数等等;
★ menu:启动菜单有关的代码;
★ scripts:一些脚本;
★ arm_config.mk:编译配置文件,其作用是给gcc增加两个编译选项;
★ config.mk:最主要的编译配置文件,其作用是生成gcc、ld等工具的编译或链接选项;
★ Makefile:工程项目管理文件;
★ mkconfig:配置生成脚本,“make Ocsom3530_config”命令执行的操作就是该脚本;
★ signGP:该程序在生成的OclO.bin上增加简单的文件头,生成可用于OMAP3530启动的文件MLO;
★ signGP.c:上一个程序的源代码,这是个PC的程序,需要PC的gcc来编译,生成的程序命名为signGP;
★ x-loader-03.00.01.06.tar.gz:TI公司发布的原版x-loader源代码,OclO基于它进行修改。
5 OclO的启动流程
(1)程序启动时的第一个文件是位于 /cpu/omap3 目录下的start.S,该程序为OclO的第一阶段,为汇编语言编写;
(2)在start.S中会调用 /board/Octagram/Ocsom3530/platform.S 中的G_ALowLevelInit函数,该函数又会调用C语言函数S_Init(位于/board/Octagram/Ocsom3530/Ocsom3530.c中),该函数会依次做下列工作:
★ 关闭看门狗;
★ 解锁存储器,这是OMAP的保护机制,不解锁,将无法写一些寄存器;
★ 配置各引脚的模式(大多数引脚是功能复用的,具体信息在《OMAP35x TRM》的第七章表7-4(772页),配置内容需查看/board/Octagram/Ocsom3530/mux.h);
★ 配置各模块需要的时钟,配置方案如下:fMPU=fDPLL1=500MHz、fIVA=fDPLL2=360MHz、fCORE=fDPLL3=332MHz、fDPLL4=432MHz;
★ 配置外部RAM。
(3)之后会建立各种模式下的堆栈,然后会跳入OclO第二阶段,第二阶段代码是用C语言编写的,入口函数为 /lib/board.c中的OclOCStage;
(4)OclOCStage函数会初始化串口作为终端设备;初始化(One)Nand;初始化SD卡;之后再等待用户输入,进入启动菜单;如果等待超时,将自动在SD卡、OneNand、Nand中寻找u-boot;如果这些操作均失败,将自动挂起,等待复位。
6 从x-loader到OclO的移植笔记(以下修改要注意大小写)
对于某些文件修改的地方比较多,因此下文没有一一列出。如果需要查看某个文件具体修改了哪些内容,可以按下面提示找到原版的文件,使用diff命令对比之。
(1)准备交叉工具链,我的工具链是自己制作的,工具前缀为arm-octagram-linux-gnueabi-,如果使用如果使用比较常用的工具链SourceryG++,前缀是arm-none-linux-gnueabi-,下载地址http://www.codesourcery.com/sgpp/lite/arm/portal/subscription?@template=lite
需要下载GNU/Linux版的,这个版本其实也是eabi版本的,使用Glibc作为C语言标准库,并且可以开发Linux系统下的程序;而EABI版的使用的是红帽的Newlib作为C语言标准库,通常不跑操作系统的CPU将使用这个工具链,例如STM32。(2)阅读Makefile文件,修改交叉工具链的前缀:
CROSS_COMPILE = "交叉工具链的路径"/arm-octagram-linux-gnueabi-
增加配置
Ocsom3530_config : unconfig @./mkconfig $(@:_config=) arm omap3 Ocsom3530 Octagram
在标签“all:”下增加
cp OclO.bin ../TftpDir ./scripts/mkMLO.sh
用于将生成的OclO.bin文件拷贝到TFTP服务器的目录下,并制作MLO文件,同时需要在“clean”命令时清除这些文件,因此修改“clean:”标签下的内容以及“clobber:”标签下的内容:
clean: find . -type f \ \( -name 'core' -o -name '*.bak' -o -name '*~' \ -o -name '*.o' -o -name '*.a' \) -print \ | xargs rm -f rm -f MLO rm -f OclO.bin OclO.map System.map OclO rm -f ../TftpDir/OclO.bin clobber: clean Find . -type f \ \( -name .depend -o -name '*.srec' -o -name '*.bin' \) \ -print \ | xargs rm -f rm -f $(OBJS) *.bak tags TAGS rm -fr *.*~ rm -f OclO OclO.map $(ALL) rm -f include/asm/proc include/asm/arch
(3)在/board文件夹下增加文件夹Octagram,在Octagram下又增加文件夹Ocsom3530,将/board/am3517中的全部内容复制到Ocsom3530文件夹下,OclO将基于这个进行修改。
(4)在Ocsom3530文件夹下有一个文件——config.mk,该文件下有个符号TEXT_BASE,这个符号表示OclO的运行地址,即OclO需要重定向到这个地址后,其中的与位置有关的代码才可以正常运行。
(5)Ocsom3530.c由am3517evm.c修改而来;新增的mux.h是功能复用的引脚配置文件;interrupts.c作用是处理中断。
(6)修改Ocsom3530文件夹下的Makefile,让其能正常编译两个.c文件。
(7)为了减少错误,先不修改start.S文件。
(8)config文件在/include/configs/Ocsom3530.h,我增加的几个符号:CONFIG_AUTOBOOT_DELAY、CONFIG_SYS_UND_STACK、CONFIG_SYS_ABT_STACK、CONFIG_SYS_IRQ_STACK、CONFIG_SYS_FIQ_STACK、CONFIG_SYS_MON_STACK、CONFIG_SYS_SVC_STACK,这些符号的意义在代码中都有注释。
(9)OMAP3530的x-loader是基于OMAP3430修改的,因此在代码中会大量出现CONFIG_OMAP3430或CONFIG_OMAP34XX,将其中“34”修改为“35”。
(10)配置外部RAM的代码位于/board/Octagram/Ocsom3530/Ocsom3530.c中的config_3530sdram_ddr函数,但是这个函数只配置了CS0,外部RAM只有128MB可用,需要增加对CS1的配置后才可以使用另外的128MB,使整个RAM可用,RAM的地址是0x80000000 ~ 0x87FFFFF和0xA0000000 ~ 0xA7FFFFFF。
(11)将/lib/board.c文件中的start_armboot改名为OclOCStage(且要也在使用到这个函数的地方修改),并增加调用I2C初始化函数(TPS65930需要使用这个总线与CPU通信,mmc部分的驱动要使用到,因为MMC1的电源是由其管理的)、调用SD卡初始化函数、进入启动菜单的代码。
(12)在/drivers文件夹中增加I2C的驱动程序:i2c.c以及在/include文件夹中增加其头文件i2c.h。
(13)原版的mmc驱动程序位于/cpu/omap3的mmc.c中,并带有三个头文件mmc_host_def.h和mmc_protocol.h,还有一个头文件在/include/asm/arch-omap3/mmc.h,但这个驱动并不适用于我的板子,原因是我的板子的MMC1的电源是由TPS65930管理,代码中缺少对TPS65930的配置,参考板子公司提供的代码,将mmc_host_def.h移动到文件夹/include/asm/arch-omap3中,删除mmc_protocol.h文件,然后还要对剩下的3个文件进行修改。为了简单,直接复制板子公司的代码过来。
(14)启动菜单的代码,需要增加一个文件夹menu,并需要编写menu.c和该目录下的Makefile,可以参考其他文件夹下的Makefile,并且需要在顶层的Makefile中增加:
LIBS += menu/libmenu.a
以增加对该文件夹下源程序的编译。
(15)在/scripts文件夹下增加生成脚本MLO文件的脚本mkMLO.sh。
(16)开始编译,出现错误提示
/home/octagram/软件/ARMTools/ocotonix/ocotonix-arm-cortex-a8/4.5.1/bin/arm-octagram-linux-gnueabi-ld: error: Source object /home/octagram/软件/ARMTools/ocotonix/ocotonix-arm-cortex-a8/4.5.1/bin/../lib/gcc/arm-octagram-linux-gnueabi/4.5.1/libgcc.a(_divsi3.o) has EABI version 5, but target OclO has EABI version 0 /home/octagram/软件/ARMTools/ocotonix/ocotonix-arm-cortex-a8/4.5.1/bin/arm-octagram-linux-gnueabi-ld: failed to merge target specific data of file /home/octagram/软件/ARMTools/ocotonix/ocotonix-arm-cortex-a8/4.5.1/bin/../lib/gcc/arm-octagram-linux-gnueabi/4.5.1/libgcc.a(_divsi3.o) /home/octagram/软件/ARMTools/ocotonix/ocotonix-arm-cortex-a8/4.5.1/bin/arm-octagram-linux-gnueabi-ld: error: Source object /home/octagram/软件/ARMTools/ocotonix/ocotonix-arm-cortex-a8/4.5.1/bin/../lib/gcc/arm-octagram-linux-gnueabi/4.5.1/libgcc.a(_dvmd_lnx.o) has EABI version 5, but target OclO has EABI version 0 /home/octagram/软件/ARMTools/ocotonix/ocotonix-arm-cortex-a8/4.5.1/bin/arm-octagram-linux-gnueabi-ld: failed to merge target specific data of file /home/octagram/软件/ARMTools/ocotonix/ocotonix-arm-cortex-a8/4.5.1/bin/../lib/gcc/arm-octagram-linux-gnueabi/4.5.1/libgcc.a(_dvmd_lnx.o) make: *** [OclO] 错误 1
根据提示,可知是EABI的版本不匹配,对于EABI(Embedded Application Binary Interface),我的认识还是有些不足,因此下面的理解可能不对。我的理解是这样的:EABI是应用程序调用的一种方式,我使用的编译器是GNU/Linux EABI,适合用来编译Linux内核及其应用程序,其对库函数等的调用方式会与Linux内核有关,与普通的EABI不同。但bootloader是不依赖操作系统的程序(bare-metal application),最佳的选择是使用普通EABI的工具链(bare-metal toolchain)来编译,例如,上面提到的SourceryG++的EABI版本。因此,若使用GNU/Linux EABI的工具链来编译OclO时,就可能发生EABI冲突。参考资料http://www.codesourcery.com/archives/arm-gnu/msg02478.html。解决的办法是把/cpu/omap3/config.mk中的编译选项
-mabi=apcs-gnu
删除,该选项指定了ABI(Application Binary Interface),即应用程序接口,有该选项后GNU/Linux EABI的工具链在连接程序时会按GNU/Linux EABI的方式来调用,而OclO不是操作系统的应用程序,因此不能有这个选项。此时编译通过了,把产生的MLO文件放入SD的FAT32主分区,能正常启动u-boot了。
(17)修改/cpu/omap3/start.S,由于原程序中的中断部分的代码不正确(可能是x-loader原先设计为使用XIP的flash直接运行,不需要ROM Code管理中断,中断向量就是标准的位于0x0处,并且x-loader也不会使用中断,所以在之后即便有问题也没有修改,而OclO是需要响应中断的)所以需要重新编写start.S文件。
(18)修改/board/Octagram/Ocsom3530/platform.S文件,删除一些不需要的代码。
(19)重新编译后发现程序启动时豪无现象,仔细排查错误,发现错误在start.S复制中断向量到ROM Code指定的内部SRAM中断向量处。由于需要复制56个字节,而使用的指令为
ldmia r0!, {r3-r10} stmia r1!, {r3-r10}
共使用了8个寄存器,这样对于56个字节需执行两次,真正复制的字节为64个,超出了8个字节,中断向量位于内部SRAM的最后,在内部SRAM之后的地址又不可访问,超出的8个字节会引发错误。因此,只能刚好复制56个字节,修改寄存器组为{r3-r9}后正常。
7. OclO下载地址:
http://download.csdn.net/source/3415264