1、从SD卡启动的逻辑分析
(1)S5PV210芯片首先会去SD卡通道0启动,启动失败才会去从SD卡通道二启动;
(2)S5PV210芯片先从SD卡中读8kb的BL1到iRAM中执行;
(3)BL1程序会把完成DDR的初始化,并把整个uboot重定位到DDR,接着执行后面的uboot代码;
S5PV210芯片的启动流程参考博客:《S5PV210的启动过程详解》。
2、制作启动SD卡
2.1、文件分析
sd_fusing
├── C110-EVT1-mkbl1.c
├── c110.signedBL1_bin
├── Makefile
├── mkbl1
├── sd_fdisk
├── sd_fdisk.c
├── sd_fusing2.sh
└── sd_fusing.sh
(1)sd_fusing.sh:在linux环境中制作启动SD卡的烧录脚本;
(2)sd_fdisk.c:编译得到sd_fdisk可执行程序,生成SD卡的MBR(主引导记录区);
(3)C110-EVT1-mkbl1.c:编译得到mkbl1,功能是截取uboot.bin的前8kb,制作成BL1;
(4)Makefile:编译脚本;
(5)sd_fusing2.sh、c110.signedBL1_bin:制作S5PV210芯片的启动SD卡用不到,应该是其他芯片使用的;
2.2、编译指令
make clean
make
./sd_fusing.sh /dev/sdb
备注:确保你的SD卡在Linux系统中是/dev/sdb,如果不是则需要改脚本;uboot.bin在上一层目录,因为在脚本里用的相对地址(…/u-boot.bin);
3、烧录脚本分析(sd_fusing.sh)
#SD卡或者mmc卡的设备文件
reader_type1="/dev/sdb"
reader_type2="/dev/mmcblk0"
#判断传入的$1是否为空
if [ -z $1 ]
then
echo "usage: ./sd_fusing.sh [/dev/sdb | /dev/mmcblk0]"
exit 0
fi
if [ $1 = $reader_type1 ]
then
partition1="$11"
partition2="$12"
partition3="$13"
partition4="$14"
elif [ $1 = $reader_type2 ]
then
partition1="$1p1"
partition2="$1p2"
partition3="$1p3"
partition4="$1p4"
else
echo "Unsupported SD reader"
exit 0
fi
#文件存在且为块设备文件
if [ -b $1 ]
then
echo "$1 reader is identified."
else
echo "$1 is NOT identified."
exit 0
fi
####################################
# make partition
echo "make sd card partition"
echo "./sd_fdisk $1"
#构建SD卡的MBR(主引导记录区),写入到0号扇区
./sd_fdisk $1
dd iflag=dsync oflag=dsync if=sd_mbr.dat of=$1
rm sd_mbr.dat
####################################
# format
umount $partition1 2> /dev/null
umount $partition2 2> /dev/null
umount $partition3 2> /dev/null
umount $partition4 2> /dev/null
#将SD卡格式化成vfat格式
echo "mkfs.vfat -F 32 $partition1"
mkfs.vfat -F 32 $partition1
#<BL1 fusing>
bl1_position=1
uboot_position=49
#截取uboot.bin的前8kb做成BL1
echo "BL1 fusing"
./mkbl1 ../u-boot.bin SD-bl1-8k.bin 8192
#将SD-bl1-8k.bin写入到SD卡的1扇区开始的地方。(扇区是编号从0开始的)
dd iflag=dsync oflag=dsync if=SD-bl1-8k.bin of=$1 seek=$bl1_position
rm SD-bl1-8k.bin
####################################
#<u-boot fusing>
echo "u-boot fusing"
# 将整个uboot写入到SD卡49扇区开始的地方,当做BL2
dd iflag=dsync oflag=dsync if=../u-boot.bin of=$1 seek=$uboot_position
####################################
#<Message Display>
echo "U-boot image is fused successfully."
echo "Eject SD card and insert it again."
(1)判断输入的设备节点类型是SD卡的还是MMC卡的;
(2)构建SD卡/MMC卡的MBR,写入到0号扇区;
(3)将SD卡/MMC卡格式化成vfat格式;
(4)调用mkbl1制作BL1,写入到1号扇区开始的地方;
(5)将uboot.bin写入到49扇区开始的地方;
4、制作BL1的代码分析(C110-EVT1-mkbl1.c)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
FILE *fp;
char *Buf, *a;
int BufLen;
int nbytes, fileLen;
unsigned int checksum;
int i;
//
if (argc != 4)
{
printf("Usage: mkbl1 <source file> <destination file> <size> \n");
return -1;
}
//
BufLen = atoi(argv[3]);
Buf = (char *)malloc(BufLen);
memset(Buf, 0x00, BufLen);
//
fp = fopen(argv[1], "rb");
if( fp == NULL)
{
printf("source file open error\n");
free(Buf);
return -1;
}
fseek(fp, 0L, SEEK_END);
fileLen = ftell(fp);
fseek(fp, 0L, SEEK_SET);
if ( BufLen > fileLen )
{
printf("Usage: unsupported size\n");
free(Buf);
fclose(fp);
return -1;
}
nbytes = fread(Buf, 1, BufLen, fp);
if ( nbytes != BufLen )
{
printf("source file read error\n");
free(Buf);
fclose(fp);
return -1;
}
fclose(fp);
//计算校验和
a = Buf + 16;
for(i = 0, checksum = 0; i < BufLen - 16; i++)
checksum += (0x000000FF) & *a++;
//保存校验和
a = Buf + 8;
*( (unsigned int *)a ) = checksum;
//
fp = fopen(argv[2], "wb");
if (fp == NULL)
{
printf("destination file open error\n");
free(Buf);
return -1;
}
a = Buf;
nbytes = fwrite( a, 1, BufLen, fp);
if ( nbytes != BufLen )
{
printf("destination file write error\n");
free(Buf);
fclose(fp);
return -1;
}
free(Buf);
fclose(fp);
return 0;
}
(1)从uboot中读出前8KB数据;
(2)计算校验和;(不包含前16字节)
(3)将校验和保存在前8kb数据的8-12字节;
(4)将添加了校验和的前8kb数据保存成文件;
5、BL1和BL2在SD中的分布
SD卡的0号扇区放的MBR(扇区引导记录),1-16扇区存放的BL1,49开始的扇区存放的完整的uboot.bin。之所以放1号扇区和49号扇区,是因为uboot源码里读BL1就是从1号扇区读,BL2就是从49号扇区读,后面会做分析。
6、S5PV210对从SD卡启动的要求
(1)iROM代码去SD卡读取BL1时,就是从1扇区开始读的,数据手册里明确写了第一个扇区要保留,这是三星官方的内置代码决定的;
(2)BL1代码有16字节的头信息,其中包含BL1的大小和校验和。其中校验和是必须填的,BL1的大小可以不填。
7、uboot启动过程中读取BL2
7.1、函数调用关系
start.S
movi_bl2_copy()
copy_bl2()
7.2、movi_bl2_copy函数分析
void movi_bl2_copy(void)
{
ulong ch;
ch = *(volatile u32 *)(0xD0037488);
copy_sd_mmc_to_mem copy_bl2 =
(copy_sd_mmc_to_mem) (*(u32 *) (0xD0037F98));
u32 ret;
if (ch == 0xEB000000) {
ret = copy_bl2(0, MOVI_BL2_POS, MOVI_BL2_BLKCNT,
CFG_PHY_UBOOT_BASE, 0);
}
else if (ch == 0xEB200000) {
ret = copy_bl2(2, MOVI_BL2_POS, MOVI_BL2_BLKCNT,
CFG_PHY_UBOOT_BASE, 0);
}
else
return;
if (ret == 0)
while (1)
;
else
return;
}
(1)0xD0037488和0xD0037F98是特殊的地址,具体查数据手册。参考博客:《ARM芯片开发(S5PV210芯片)——SD卡启动》;
(2)读取0xD0037488地址处的数据,判断是从SD卡通道0还是从SD卡通道2读取BL2;
(3)copy_bl2函数功能:从SD卡通道0/2的MOVI_BL2_POS扇区开始处读取MOVI_BL2_BLKCNT个扇区的数据,放到CFG_PHY_UBOOT_BASE地址(内存地址)处;
(4)宏定义是在uboot的源码里定义的,MOVI_BL2_POS–49,MOVI_BL2_BLKCNT–1024,CFG_PHY_UBOOT_BASE–0x33e00000;