Exynos4412的启动过程

做实验时我们是把bin文件烧入SD卡。是谁把这些指令从SD卡读出来执行?是固化在芯片内部ROM上的代码──它被称为iROM,iROM是厂家事先烧写在芯片上的,无源码。

iROM把启动设备上特定位置处的程序读入片内内存(iRAM),并执行它。这个程序被称为BL1(Bootloader 1),BL1是三星公司提供的,无源码。

BL1又把启动设备上另一个特定位置处的程序读入片内内存,并执行它。这个程序被称为BL2(Bootloader 2),是我们编写的源码。

iROM、BL1更细致的启动过程如下。图1是iROM启动流程图。

                                                                                    图1. iROM启动流程

简单地说,就是先设置程序运行环境(比如关看门狗、关中断、关MMU、设置栈、启动PLL等等);然后根据OM引脚确定启动设备(NAND Flash/SD卡/其他),把BL1从里面读出存入iRAM;最后启动BL1。

图2是BL1的启动过程。

                                                  图2. BL1启动流程

简单地说,也是设置程序运行环境(初始化中断、设置栈等等);然后从启动设备上把BL2读入iRAM;最后启动它。

有几个问题需要解决:

  1. 在启动设备上哪个位置存放BL1、BL2?
  2. 把BL1、BL2读到iRAM那个位置?
  3. BL1、BL2大小是?
  4. 怎么保证BL1、BL2程序的完整性(即读出程序时没有错误)?

假设启动设备为SD卡,如图3、图4所示:

                                                                   图3. BL1/BL2在SD卡上的存储位置

                   图4. BL1/BL2在iRAM中的存储位置

BL1位于SD卡偏移地址512字节处,iROM从这个位置读入8K字节的数据,存在iRAM地址0x02021400位置处。所以BL1不能大于8K。

BL2位于SD卡偏移地址(512+8K)字节处,BL1从这个位置读入16K字节的数据,存在iRAM地址0x02023400处。BL2不能大于(16K-4)字节,最后4字节用于存放较验码。

如果我们的程序大于(16K-4)字节,那么需要截取前面(16K-4)字节用来制作BL2并烧入SD卡偏移地址16K字节处。当BL2启动后,由它来将存放在SD卡另外位置的、完整的程序读入内存。

对于其他启动设备,可以参考《Android_Exynos4412_iROM_Secure_Booting_Guide_Ver.1.00.00.pdf》。

板子一上电,首先执行iROM,iROM依次尝试从第1个SD 卡、NAND Flash、第2个SD卡、Nor Flash上把程序读入iRAM中,一旦从某个设备上成功读出程序就会去启动它。

在前面的实验过程中,我们都是通过sd_fusing.sh这个脚本文件,一键烧写程序到SD卡中。我们分析该脚本程序,发现其核心命令就3条:

01 dd iflag=dsync oflag=dsync if=/work/4412/tools/E4412_N.bl1.bin of=$1 seek=$signed_bl1_position
02 dd iflag=dsync oflag=dsync if=./bl2.bin of=$1 seek=$bl2_position
03 sync

第1行的命令用于将E4412_N.bl1.bin烧写到SD卡的第1个扇区(扇区从0编号);
第2行的命令用于将bl2.bin烧写到SD卡的第17个扇区;
第3行的命令用于将内存缓冲区内的数据写入磁盘。

E4412_N.bl1.bin(BL1)是由三星原厂提供,没有源码,它的作用在前面稍有介绍。

bl2.bin是通过mkbl2工具处理源文件得到,具体实现如下:

./mkbl2 led.bin bl2.bin 14336

mkbl2是用来生成bl2.bin的工具,通过编译V310-EVT1-mkbl2.c文件得到,具体如下:

gcc -o mkbl2 V310-EVT1-mkbl2.c

通过分析V310-EVT1-mkbl2.c源码,我们可以知道,它主要做了这些工作:
1).从源文件中读取14K的数据到Buf当中;
2).处理Buf中前14332字节的数据,得到4字节的checksum;
3).组装Buf中前14332字节的数据和4字节的checksum,得到一个新的14K的Buf数据;
4).将3)中构建的Buf数据写到bl2.bin文件中。

裸板烧写过程:

BL1对应的文件是E4412_N.bl1.bin。

BL2是根据我们提供的程序来制作的,此工具的源码是V310-EVT1-mkbl2.c,我们在里面添加了注释,可用以下命令生成可执行程序mkbl2:

gcc -o mkbl2 V310-EVT1-mkbl2.c

mkbl2的作用是截取用户提供的bin文件的前(14K-4)字节数据,算出4字节的较验码,然后这两部分数据组合成14KB的文件bl2.bin,它就是BL2。

对于SD卡,我们只需要把E4412_N.bl1.bin烧在偏移地址512字节处,把bl2.bin烧在偏移地址(512+8K)字节处。

如果用户提供的bin大于(14K-4)字节,还需要把它烧写在SD卡其他位置,这由用户决定。我们的大部分程序没超过(14K-4)字节,所以这种情况暂时不理会。

对于SD卡,烧写过程总结如下:

把E4412_N.bl1.bin烧在偏移地址512字节处
使用mkb12命令,把用户提供的bin文件制作出bl2.bin,命令如下(修改bin文件名为led.bin):

./mkbl2 led.bin bl2.bin 14336

把bl2.bin烧在偏移地址(512+8K)字节处。

为简单化操作,我们把这些命令写入sd_fusing.sh文件中,使用时只要执行以下命令即可(假设SD卡的设备节点为/dev/sdb,用户bin文件为led.bin):

sudo ./sd_fusing.sh /dev/sdb led.bin

注意:把SD卡接到PC后执行以下命令,一般最后一个"不带数字的"设备节点就是SD卡的设备名:

$ ls /dev/sd*
输出示例:
brw-rw---- 1 root disk 8,  0 Nov 18 09:22 /dev/sda
brw-rw---- 1 root disk 8,  1 Nov 18 09:22 /dev/sda1
brw-rw---- 1 root disk 8,  2 Nov 18 09:22 /dev/sda2
brw-rw---- 1 root disk 8,  5 Nov 18 09:22 /dev/sda5
brw-rw---- 1 root disk 8, 16 Nov 18 20:48 /dev/sdb
brw-rw---- 1 root disk 8, 17 Nov 18 20:48 /dev/sdb1

在上面的输出示例中,/dev/sdb就是该卡的设备名。

sd_fusing.sh的源码如下(注释很完善,不用再讲解):

#已经做了详细的注释,不再讲解
if [ -z $1 ] 			#判断参数1的字符串是否为空,如果为空,则打印出帮助信息
	then
		echo "usage: sd_fusing.sh <SD Reader's device file> <Source file>"
		exit 0
fi

if [ -z $2 ] 			#判断参数2的字符串是否为空,如果为空,则打印出帮助信息
	then
		echo "usage: sd_fusing.sh <SD Reader's device file> <Source file>"
		exit 0
fi

if [ -b $1 ] #判断参数1所指向的设备节点是否存在
	then
		echo "$1 reader is identified."
	else
		echo "$1 is NOT identified."
		exit -1
fi

####################################
#<verify device>
BDEV_NAME=`basename $1`													# sdb
BDEV_SIZE=`cat /sys/block/${BDEV_NAME}/size`		# 获取SD容量的大小

#如果卡的容量小于0,则打印失败信息,并退出
if [ ${BDEV_SIZE} -le 0 ]; then
	echo "Error: NO media found in card reader."
	exit 1
fi

#如果卡的容量大于32000000,则打印失败信息,并退出
if [ ${BDEV_SIZE} -gt 32000000 ]; then
	echo "Error: Block device size (${BDEV_SIZE}) is too large"
	exit 1
fi

####################################
# check files
SOURCE_FILE=$2
MKBL2=mkbl2
#检查source file是否存在
if [ ! -f ${SOURCE_FILE} ]; then
	echo "Error: $2 NOT found, please build it & try again."
	exit -1
fi

#制作bl2.bin文件
#使用mkbl2工具来处理传入的bin,从而生成bl2.bin
${MKBL2} ${SOURCE_FILE} bl2.bin 14336

####################################
# fusing images
signed_bl1_position=1 		# bl1的镜像烧写到sd卡的第1个扇区   每个扇区大小为512
bl2_position=17 					# bl2的镜像烧写到sd卡的第17个扇区

#<BL1 fusing>
echo "---------------------------------------"
echo "BL1 fusing"
# 烧写bl1到SD卡512字节处
dd iflag=dsync oflag=dsync if=/work/tiny4412/sd_fuse/tiny4412/E4412_N.bl1.bin of=$1 seek=$signed_bl1_position

# 如果失败则退出
if [ $? -ne 0 ]
	then
		echo Write BL1 Error!
		exit -1
fi

#<BL2 fusing>
echo "---------------------------------------"
echo "BL2 fusing"
# 烧写bl2到SD卡(512+8K)字节处, 512+8K=17x512,即第17个block
dd iflag=dsync oflag=dsync if=./bl2.bin of=$1 seek=$bl2_position

# 如果失败则退出
if [ $? -ne 0 ]
	then
		echo Write BL2 Error!
		exit -1
fi

#<flush to disk>
# 同步文件
sync

#删除bl2.bin文件
rm bl2.bin

####################################
#<Message Display>
echo "---------------------------------------"
echo "source file image is fused successfully."
echo "Eject SD card and insert it to Exynos 4412 board again."

连接脚本分析:

以gpio_led目录下的led.lds为例,它的内容如下:

SECTIONS {
	. = 0x02023400;
	.text : { *(.text) }
	.rodata ALIGN(4) : {*(.rodata*)}
	.data ALIGN(4) : { *(.data*) }
	.bss ALIGN(4) : { *(.bss) *(COMMON) }
}

第2行表示程序的连接地址从0x02023400开始,这表示我们的程序运行之前,应该位于内存地址0x02023400字节处。BL1会把BL2复制到0x02023400地址处,再启动它。

第3~6行,表示从0x02023400开始,依次排放程序的代码段、只读数据段、数据段、BSS段。

猜你喜欢

转载自blog.csdn.net/caihaitao2000/article/details/84203856
今日推荐