Cortex-A8中bootloader研究(2)

上篇文章中,讲到Bootloader执行完成之后,系统运行环境搭建完成,本篇继续分析后续应用程序的引导流程。

AM335x支持的启动方式有很多种,包括SPI,UART,NAND FLASH以及SD卡,针对于beaglebone板子,支持UART启动和SD卡启动,这里仅仅分析从SD卡启动。内容包括从SD卡读取应用程序bin文件并将其复制到RAM中,确定函数的入口点,启动应用程序,对这一部分内容做详细论述。

1. 应用程序的装载

该功能的实现主要通过ImageCopy()函数实现。

重要的数据结构:

//ti_header结构体,用于存储应用程序大小及起始地址
    typedef struct _ti_header_
    {
        unsigned int image_size;  
        unsigned int load_addr; 
    }ti_header;
ti_header imageHdr;
// g_cCwdBuf[512],用于装载应用程序所在路径,以’/’字符开头
#define PATH_BUF_SIZE   512
static char g_cCwdBuf[PATH_BUF_SIZE] = "/";
//指向应用程序的文件指针
static  FIL  g_sFileObject;

装载流程

代码的层面上来阐述上述实现的具体过程。

(1)目标文件路径的填充

应用程序放置在SD卡的根目录下,需要将目录及文件名赋值给路径变量空间。

g_cCwdBuf[0] = '/';
g_cCwdBuf[1] = '\0';
/* *赋值到备份空间域* */
strcpy(g_cTmpBuf, g_cCwdBuf);
……
//将应用程序名粘贴到路径之后,最终路径为”/app”
strcat(g_cTmpBuf, "app");

经过上述操作之后,路径空间中内容为”/app”。由此可知,复制到SD卡中的应用程序文件名必须为app,这样才能被访问。

(2)文件指针指向该文件

fresult = f_open(&g_sFileObject, g_cTmpBuf, FA_READ);

将路径g_cTmpBuf指定的文件(这里为/app)指向g_sFileObject文件指针,并返回读取状态。

(3)装载地址信息的读取

fresult = f_read(&g_sFileObject, (unsigned char *)&imageHdr, 8,&usBytesRead);

读取目标文件前八个字节并放置到imageHdr结构体中。函数形参中将imageHdr指针强制转化成char型指针用以实现字节为单位的复制。imageHdr结构体高四位表示目标文件的大小,后四字节表示目标文件将要被装载到得地址。
问题:这八个字节的信息是如何被放置在应用程序bin文件的高八位的?是不是通过Makefile文件中特别配置编译产生的?

(4)装载地址的保存

destAddr = (unsigned char*)imageHdr.load_addr;
entryPoint = imageHdr.load_addr;

这两种保存是由差别的,destAddr定义为char*型,该赋值语句首先将unsigned int型的变量imageHdr.load_addr转换成unsigned char*指针类型,再赋值给destAddr,该变量用于下面的文件赋值,即将目标文件以字节为单位从SD卡复制到RAM中。后面一个赋值语句直接将地址值imageHdr.load_addr赋值给entryPoint变量,该变量将用于程序的启动,后面将会看到。

(5)目标文件的复制

该过程将目标文件从SD卡复制到RAM中,使用f_read函数

fresult = f_read(&g_sFileObject, g_cTmpBuf, sizeof(g_cTmpBuf) - 1,&usBytesRead);

一次读取511个字节集,第512个字节放置’\0’字符,并将其复制到RAM空间,当某次读取的数量小于511时,即认为本次读取已经到了文件结尾,退出该过程。

2. 目标文件启动

目标文件的启动有赖于上述装载地址的保存,由上面可知,应用程序装载在entryPoint指定的起始地址中,要利用该地址完成程序的启动,需要以下几个工作:

//定义一个函数指针
static void (*appEntry)();
//函数指针赋值为应用程序入口点
appEntry = (void (*)(void)) entryPoint;
//启动应用程序
(*appEntry)( );

其中第二句,将unsigned int型变量entryPoint转换成返回值为空型(前一个void的作用),形参为空(后一个void的作用)的函数指针,再赋值给函数指针appEntry。第三句直接通过函数指针启动应用程序,这是一个函数指针在嵌入式系统中的典型例子。至此,bootloader工作完成。

3.bootloader的编译

bootloader的编译既可以通过CCS进行,也可以通过Linux环境下的Makefile进行,CCS下的编译看不到相关的配置,这里选择分析Linux环境下的Makefile编译方式,来研究bootloader的编译方式和相关配置。

bootloader的Makefile文件如下,红色为注释:

# 定位到starterware的根目录
ROOT=../../../../../../
#定义设备和开发板版本,用于的路径搜寻
DEVICE=am335x
EVM=beaglebone
#包含makedefs文件,该文件内定义了相关路径
include ${ROOT}/build/armv7a/gcc/makedefs
#指定编译所依赖的文件的路径,该路径在上述makedefs中被定义
DIRS=${DRIVERS_BLD} ${PLATFORM_BLD} ${UTILITY_BLD} ${MMCSDLIB_BLD} ${NANDLIB_BLD}
#指定生成文件的文件名
APPDIR=bootloader
APPNAME=boot
#bootloader将要被装载到得空间,重要的变量
START_ADDR=0x402F0400
#生成文件的文件位置
APP=${ROOT}bootloader/
APP_BIN=${ROOT}/binary/${TARGET}/${COMPILER}/${DEVICE}/${EVM}/$(APPDIR)
#bootloader编译需要的C文件
COMMON=$(APP)src/bl_main.c\
       $(APP)src/bl_am335x.c\
       $(APP)src/bl_copy.c\
       $(APP)src/bl_pmI2c.c\
       $(APP)src/bl_pmic.c\
       $(APP)src/$(TARGET)/gcc/*.S
#SD卡启动时需要的C文件
ifeq ($(BOOT), MMCSD)
SOURCE=$(APP)/src/bl_hsmmcsd.c \
       $(FATFS_SRC)/src/ff.c       \
       $(FATFS_SRC)/port/fat_mmcsd.c
endif
#UART启动时需要的C文件
ifeq ($(BOOT), UART)
SOURCE=$(APP)/src/bl_uart.c \
       ${ROOT}/third_party/xmodem/xmodem.c \
       ${ROOT}/third_party/xmodem/crc16.c
endif

APP_SRC=$(SOURCE) $(COMMON)
#需要的库文件
APP_LIB=-ldrivers  \
    -lutils    \
    -lplatform \
    -lmmcsd 
#编译
all: debug release

debug:
    make TARGET_MODE=debug lib
    make TARGET_MODE=Debug bin

release:
    make TARGET_MODE=release lib
    make TARGET_MODE=Release bin

lib:
    @for i in ${DIRS};             \
    do                      \
        if [ -f $${i}/makefile ] ;		    \
		then					  \
			make $(TARGET_MODE) -C $${i} || exit $$?; \
        fi;                    \
    done;
bin:
    $(CC)  $(CFLAGS) $(APP_SRC)
    @mkdir -p $(TARGET_MODE)/
    @mv *.o* $(TARGET_MODE)/
    $(LD) ${LDFLAGS} ${LPATH} -o $(TARGET_MODE)/$(APPNAME).out -Map $(TARGET_MODE)/$(APPNAME).map \
 $(TARGET_MODE)/*.o*  --defsym BOOT_START_ADDR=$(START_ADDR) -T $(APPNAME).lds $(APP_LIB) -lc -lgcc $(APP_LIB) -lc -lgcc 
    @mkdir -p $(APP_BIN)/$(TARGET_MODE)
    @cp $(TARGET_MODE)/$(APPNAME).out $(APP_BIN)/$(TARGET_MODE)/$(APPNAME).out
    $(BIN) $(BINFLAGS) $(APP_BIN)/$(TARGET_MODE)/$(APPNAME).out \
               $(APP_BIN)/$(TARGET_MODE)/$(APPNAME).bin 
    cd $(ROOT)/tools/ti_image/; gcc tiimage.c -o a.out; cd - 
           $(ROOT)/tools/ti_image/a.out $(START_ADDR) $(BOOT) \
               $(APP_BIN)/$(TARGET_MODE)/$(APPNAME).bin \
               $(APP_BIN)/$(TARGET_MODE)/$(APPNAME)_ti.bin; rm -rf $(ROOT)/tools/ti_image/a.out;
#清除Release文件 需要make clean显式执行
clean:
    @rm -rf Debug Release $(APP_BIN)/Debug $(APP_BIN)/Release
clean+: clean
    @make TARGET_MODE=clean lib

对Makefile的分析,仅仅对bootloader编译文件依赖方面理解的较为清除,具体编译的细节参数,尚未理解透彻,需要对gcc编译的相关参数做学习,有研究的朋友可以进一步补充。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值