1. CFE
中的splash
CFE
启动后,初始化各种设备,然后初始化显示相关的寄存器,从flash
中读取图片splash.bmp
并绘制到surface memory
区域。
由于splash
存放在flash
的分区中,所以必须要等待flash
驱动完成初始化后,读取出图像splash.bmp
才能显示。
那如果想CFE
一启动就显示splash
呢?显然最好是将splash.bmp
嵌入到代码中。
本文基于机顶盒上使用的CFE v15.2
版本将splash.bmp
编译嵌入到cfe.bin
中,并在启动时显示图像。
2. 生成可连接的目标文件splash.bmp.o
GNU binutils
的objcopy
工具用途比较广泛,其中一项就是各种目标文件之间的转换。
因此使用objcopy
可以将任意文件转换为可以连接的目标文件,参与生成最终的可以执行文件。
2.1 sde-objcopy
CFE
编译使用MIPS
提供的工具套件MIPS SDE v5.03
,这是一个相当老的工具套件了,gcc
版本只有2.96
,objcopy
版本为2.9
,如下:
ygu@ubuntu:/opt/cfe_v15.2$ sde-gcc -v
Reading specs from /opt/toolchains/sde-v5.03/bin/../lib/gcc-lib/sde/2.96-mipssde-031117/specs
gcc version 2.96-mipssde-031117
ygu@ubuntu:/opt/cfe_v15.2$ sde-objcopy -V
GNU objcopy 2.9-mipssde-031003
Copyright 1997, 98, 99, 2000 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License. This program has absolutely no warranty.
对于sde-objcopy
甚至还不支持-B
选项,我曾经尝试用sde-objcopy
去转换splash.bmp
,但最终都失败了。最后手动用编译应用的mipsel-linux-objcopy
将splash.bmp
转换为可连接的目标文件splash.bmp.o
后,再将这个可连接文件用于最终CFE
的生成。
2.2 使用mipsel-linux-objcopy
工具进行转换
2.2.1 -B mipsisa32
选项
转换命令如下(此处使用的是stbgcc-4.5.4-2.9
包中的objcopy
):
ygu@ubuntu:/opt/cfe_v15.2$ mipsel-linux-objcopy -I binary -O elf32-tradlittlemips -B mipsisa32 splash.bmp splash.bmp.o
用file
命令查看生成的可连接文件:
ygu@ubuntu:/opt/cfe_v15.2$ file splash.bmp.o
splash.bmp.o: ELF 32-bit LSB relocatable, MIPS, MIPS32 version 1 (SYSV), not stripped
再用file
查看下cfe
编译生成的其它文件,如cfe_main.o
:
ygu@ubuntu:/opt/cfe_v15.2/build/7584$ file cfe_main.o
cfe_main.o: ELF 32-bit LSB relocatable, MIPS, MIPS32 version 1 (SYSV), not stripped
可见手动生成的splash.bmp.o
和cfe_main.o
格式是一致的。
2.2.2 -B mips
选项
如果objcopy
使用-B mips
而不是-B mipsisa32
选项进行转换,则由于指定cpu
架构不一致而存在问题。
ygu@ubuntu:/opt/cfe_v15.2$ mipsel-linux-objcopy -I binary -O elf32-tradlittlemips -B mips splash.bmp splash.bmp.o
ygu@ubuntu:/opt/cfe_v15.2$ file splash.bmp.o
splash.bmp.o: ELF 32-bit LSB relocatable, MIPS, MIPS-I version 1 (SYSV), not stripped
仔细查看file
命令的输出,这里生成的是MIPS-I version 1
的格式,跟CFE
原生编译生成的格式不一样。
2.3 使用nm
工具检查符号
使用objcopy
工具生成的可连接文件objfile
会内置三个位置相关的符号变量_binary_objfile_start
, _binary_objfile_end
和_binary_objfile_size
,可以用nm
工具查看。
这里使用mipsel-linux-nm
检查生成文件splash.bmp.o
中的符号:
ygu@ubuntu:/opt/cfe_v15.2$ mipsel-linux-nm -a splash.bmp.o
00000000 d .data
0006b892 D _binary_splash_bmp_end
0006b892 A _binary_splash_bmp_size
00000000 D _binary_splash_bmp_start
可见生成了三个符号变量,名字也很直观:
+ _binary_splash_bmp_start
指示bmp
数据开始的位置
+ _binary_splash_bmp_end
指示bmp
数据结束的位置
+ _binary_splash_bmp_size
指示bmp
数据的大小
3. CFE
链接splash.bmp.o
将生成的splash.bmp.o
放到splash
目录下,然后在编译系统中添加对splash.bmp.o
的编译引用:
3.1 链接splash.bmp.o
生成ssbl
在cfe_link.mk
文件中修改ssbl
的生成规则,让其链接splash.bmp.o
:
ssbl ssbl.bin: $(DEV_OBJS) $(COMMON_OBJS) $(ECM_OBJS) $(LIBCFE) splash.bmp.o
$(GLD) -o ssbl -Map ssbl.map $(SSBL_LDFLAGS) -L. $(DEV_OBJS) $(COMMON_OBJS) $(ECM_OBJS) splash.bmp.o -lcfe $(LDLIBS)
3.2 复制splash.bmp.o
到编译目录
3.1节中指定的splash.bmp.o
默认的位置在build/7xxx
下,即跟编译生成的文件在同一个地方,但我们预先生成了splash.bmp.o
,所以还需要添加规则将splash.bmp.o
从splash
目录复制到当前目录来。
在cfe.mk
中添加这个规则:
# copy splash/splash.bmp.o to build dir
splash.bmp.o : ../../splash/splash.bmp.o
@echo 'copy $(notdir $<)'
@cp -rf $< $@
添加以上两个规则后,就可以顺利将splash.bmp.o
嵌入到生成的cfe.bin
中了。
3.3 编译时生成`splash.bmp.o
如果预先设置了mipsel-linux-objcopy
的路径也可以在编译时才生成splash.bmp.o
,则cfe.mk
中生成splash.bmp.o
的规则如下:
splash.bmp.o : splash.bmp
@echo 'mipsel-linux-objcopy $(notdir $<)'
@mipsel-linux-objcopy -I binary -O elf32-tradlittlemips -B mipsisa32 $^ $@
4. CFE
中引用splash.bmp.o
的数据
默认情况下,CFE
的cfe_splash
函数会先从flash
中读取图片,然后再显示。
这里我们对这个函数稍作修改,使其直接显示cfe.bin
中内嵌的图片,修改如下:
(cfe_main.c
中的cfe_splash
函数)
/* 声明splash.bmp.o中的位置相关的外部变量 */
extern unsigned long _binary_splash_bmp_start;
extern unsigned long _binary_splash_bmp_end;
extern unsigned long _binary_splash_bmp_size;
void cfe_splash()
{
BMP_HEADER_INFO bmpinfo[2];
int x,y;
void *surfaceMemory[2];
void *bmpMemory[2];
int ii;
/* PORT POINT: if you have more than 2 surfaces */
surfaceMemory[0] = (void *)PHYS_TO_K0(SURFACE_MEM_ADDRS);
surfaceMemory[1] = (void *)PHYS_TO_K0(SURFACE_MEM_ADDRS_1);
/* 直接引用bmp数据的起始地址 */
bmpMemory[0] = (void *)&_binary_splash_bmp_start;;
bmpMemory[1] = (void *)&_binary_splash_bmp_start;;
for(ii=0; ii<g_ulNumSurface; ii++)
{
/* 解析bmp头部结构,获取bmp图片信息 */
if(splash_bmp_getinfo(bmpMemory[ii], &bmpinfo[ii]) != 0 ||
bmpinfo[ii].header.size > SPLASH_IMAGE_SIZE ||
bmpinfo[ii].header.offset > SPLASH_HDR_SIZE)
{
if (ii == 0)
{
xprintf("No valid image found in " SPLASH_IMAGE_FILE " - disabling splash\n");
return ;
}
else
{
bmpinfo[ii] = bmpinfo[0];
}
}
/* 输出bmp的一些调试信息 */
xprintf("Found splash image %d - Width = %d Height = %d at: [0x%08x - 0x%08x, %d bytes]\n",
ii, bmpinfo[ii].info.width, bmpinfo[ii].info.height,
(unsigned long *)&_binary_splash_bmp_start,
(unsigned long *)&_binary_splash_bmp_end,
(unsigned long)&_binary_splash_bmp_size);
#ifdef SPLASH_SURFACE_SELECT_ENABLED
surfaceMemory[ii] = g_pvSplashSurfaceAddr[ii];
#endif
BMEM_ConvertAddressToOffset(NULL, surfaceMemory[ii], &g_SplashInfo.aulSurfaceBufOffset[ii]);
}
splash_bvn_init(NULL, &g_SplashInfo);
/* 以下部分没有修改,同原函数 */
...
}
修改后编译生成cfe.bin
,烧写到机顶盒上就可以在开机启动时显示内嵌到cfe
里面的图像数据。
5. 其它
不仅可以转换图片数据,objcopy
还可以将任何格式的文件转换为可连接的目标文件,如字体、固件等,比较灵活也比较方便。