每一段程序的诞生,都是神圣而伟大的……
今天,我们就来见证这神圣而伟大的时刻!
上一篇《Exynos4412 启动过程 - bootloader的一生》,我们主要了解了系统的启动过程,iRAM --> BL1 --> BL2 --> 启动OS
其中,iRAM固化在芯片里,iRAM会根据OM Pin,选择从哪种启动介质(SD,NAND Flash,eMMc等)加载并运行BL1,BL1再加载BL2(如果有的话),BL2再启动OS。
iRAM固化在芯片里,只要芯片没坏,硬件电路设计正确,一启动,就必然会先执行iRAM代码。
BL1由三星提供,BL2可能由三星提供(pop封装),也可能从编译生成的代码中取14k(scp封装),启动OS前呢,要初始化系统,构建系统所能运行的环境,是自个编译的。
所以,u-boot的构成,可能会是 BL1+BL2+其它。
这一篇,我们以迅为开发板的uboot为例,编译、生成、烧录,了解整个uboot的诞生。
本人板卡使用 samsung exynos4412 POP封装的,内置1GDDR。
1、 解压:注意,一定要拷在linux系统下解压,不能在window下解压,除非,你只想看一看代码。
2、 ./build_sh POP_1GDDR(因为我的芯片是 POP_1GDDR的,如果哪位是 SCP的,请选择别的参数)
3、 等一大会...
就这样,编译和生成都一步到位,生成的u-boot-iTOP-4412.bin,就是要烧录的bin文件。
5.28日 11:19,成功诞下u-boot,男女未知?重45465字节。名u-boot-iTop-4412.bin
上一篇《Exynos4412 启动过程 - bootloader的一生》我们讲过,iRAM会根据 OM Pin,选择启动介质。
这个启动介质可以是 SD卡,eMMC等,得先把生成的 u-boot-iTop-4412.bin,写进启动介质里面。
板子刚出厂的时候,除了 iROM之外,eMMC,SD等存储介质,是没有任何程序的,系统一上电,就只能运行 iROM程序。
我们就选择SD卡启动吧。为什么不选择eMMC呢?因为eMMC是焊在板子上的啊,你得把它取下来,烧好了,再焊上去,麻烦。
选择 SD 卡启动,就要把 u-boot-iTop-4412.bin 写进 SD 卡里面。
1、 插入SD卡。
2、 ./mkuboot /dev/sdb
3、 等一小会...
就这样,把u-boot_itop412.bin写进SD卡里面。
把拨码开关设置至xxxx,看上一篇的OM Pin选择。
插入SD卡,连上串口线,开机,这就是u-boot的启动界面,至此,bootloader的使命结束。
PS:一般来说,这就是 u-boot,u-boot的作用仅仅只是引导系统,在实际应用中,我们会把u-boot,内核,文件系统,统统烧录进emmc里面,由板载的emmc引导,启动。该过程类似于安装操作系统,emmc相当于硬盘,SD卡相当于U盘安装盘。图中,由于在 mmc 里面没有找到内核和文件系统,所以最终无法启动操作系统。
我们从 ./build_sh 开始,一步步来了解一下,u-boot 的形成机制。
这是一个 shell 脚本,不熟悉 shell 脚本的同学,请移步《linux shell 脚本 - 给男友的家务清单》
完整的 build_uboot.sh 文件如下:
#!/bin/sh
if [ -z $1 ]
then
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "Please use correct make config.for example make SCP_1GDDR for SCP 1G DDR CoreBoard linux,android OS"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
exit 0
fi
if [ "$1" = "SCP_1GDDR" ] || [ "$1" = "SCP_2GDDR" ] || [ "$1" = "SCP_1GDDR_Ubuntu" ] || [ "$1" = "SCP_2GDDR_Ubuntu" ]
then
sec_path="../CodeSign4SecureBoot_SCP/"
CoreBoard_type="SCP"
elif [ "$1" = "POP_1GDDR" ] || [ "$1" = "POP_1GDDR_Ubuntu" ]
then
sec_path="../CodeSign4SecureBoot_POP/"
CoreBoard_type="POP"
elif [ "$1" = "POP_2GDDR" ] || [ "$1" = "POP_2GDDR_Ubuntu" ]
then
sec_path="../CodeSign4SecureBoot_POP/"
CoreBoard_type="POP2G"
else
echo "make config error,please use correct params......"
exit 0
fi
CPU_JOB_NUM=$(grep processor /proc/cpuinfo | awk '{field=$NF};END{print field+1}')
ROOT_DIR=$(pwd)
CUR_DIR=${ROOT_DIR##*/}
#clean
make distclean
#rm link file
rm ${ROOT_DIR}/board/samsung/smdkc210/lowlevel_init.S
rm ${ROOT_DIR}/cpu/arm_cortexa9/s5pc210/cpu_init.S
case "$1" in
clean)
echo make clean
make mrproper
;;
*)
if [ ! -d $sec_path ]
then
echo "**********************************************"
echo "[ERR]please get the CodeSign4SecureBoot first"
echo "**********************************************"
return
fi
if [ "$1" = "SCP_1GDDR" ]
then
make itop_4412_android_config_scp_1GDDR
elif [ "$1" = "SCP_2GDDR" ]
then
make itop_4412_android_config_scp_2GDDR
elif [ "$1" = "POP_1GDDR" ]
then
make itop_4412_android_config_pop_1GDDR
elif [ "$1" = "POP_2GDDR" ]
then
make itop_4412_android_config_pop_2GDDR
elif [ "$1" = "SCP_1GDDR_Ubuntu" ]
then
make itop_4412_ubuntu_config_scp_1GDDR
elif [ "$1" = "SCP_2GDDR_Ubuntu" ]
then
make itop_4412_ubuntu_config_scp_2GDDR
elif [ "$1" = "POP_1GDDR_Ubuntu" ]
then
make itop_4412_ubuntu_config_pop_1GDDR
elif [ "$1" = "POP_2GDDR_Ubuntu" ]
then
make itop_4412_ubuntu_config_pop_2GDDR
fi
make -j$CPU_JOB_NUM
if [ ! -f checksum_bl2_14k.bin ]
then
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "There are some error(s) while building uboot, please use command make to check."
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
exit 0
fi
cp -rf checksum_bl2_14k.bin $sec_path
cp -rf u-boot.bin $sec_path
rm checksum_bl2_14k.bin
cd $sec_path
#./codesigner_v21 -v2.1 checksum_bl2_14k.bin BL2.bin.signed.4412 Exynos4412_V21.prv -STAGE2
# gernerate the uboot bin file support trust zone
#cat E4412.S.BL1.SSCR.EVT1.1.bin E4412.BL2.TZ.SSCR.EVT1.1.bin all00_padding.bin u-boot.bin E4412.TZ.SSCR.EVT1.1.bin > u-boot-iTOP-4412.bin
if [ "$CoreBoard_type" = "SCP" ]
then
cat E4412_N.bl1.SCP2G.bin bl2.bin all00_padding.bin u-boot.bin tzsw_SMDK4412_SCP_2GB.bin > u-boot-iTOP-4412.bin
elif [ "$CoreBoard_type" = "POP" ]
then
cat E4412.S.BL1.SSCR.EVT1.1.bin E4412.BL2.TZ.SSCR.EVT1.1.bin all00_padding.bin u-boot.bin E4412.TZ.SSCR.EVT1.1.bin > u-boot-iTOP-4412.bin
elif [ "$CoreBoard_type" = "POP2G" ]
then
cat bl2.bin u-boot.bin E4412.TZ.SSCR.EVT1.1.bin > u-boot-iTOP-4412.bin
else
echo "make uboot image error......"
fi
mv u-boot-iTOP-4412.bin $ROOT_DIR
rm checksum_bl2_14k.bin
#rm BL2.bin.signed.4412
rm u-boot.bin
echo
echo
;;
esac
其中,关键的部分:
make itop_4412_android_config_pop_1GDDR
make -j$CPU_JOB_NUM
这两行生成 u-boot.bin。
make itop_4412_android_config_pop_1GDDR 生成各种配置文件,稍候我们仔细研读一下 Makefile自然了解;
make -j$CPU_JOB_NUM 这个看你多少核 cpu,在我的电脑是,就是 make -j4,直接 make 也是可以的,只是编译的速度,比 make -j4 慢而已;
cd $sec_path
cat E4412.S.BL1.SSCR.EVT1.1.bin E4412.BL2.TZ.SSCR.EVT1.1.bin all00_padding.bin u-boot.bin E4412.TZ.SSCR.EVT1.1.bin > u-boot-iTOP-4412.bin
这两行生成 u-boot-iTOP-4412.bin
sec_path="../CodeSign4SecureBoot_POP/" 在make 之前已经设置好了。
cd $sec_path 相当于进入 ../CodeSign4SecureBoot_POP/ 目录
cat E4412.S.BL1.SSCR.EVT1.1.bin E4412.BL2.TZ.SSCR.EVT1.1.bin all00_padding.bin u-boot.bin E4412.TZ.SSCR.EVT1.1.bin > u-boot-iTOP-4412.bin
E4412.S.BL1.SSCR.EVT1.1.bin + E4412.BL2.TZ.SSCR.EVT1.1.bin + all00_padding.bin + u-boot.bin + E4412.TZ.SSCR.EVT1.1.bin 拼起来,形成 u-boot-iTOP-4412.bin
u-boot.bin 由我们编译而成,E4412.S.BL1.SSCR.EVT1.1.bin、E4412.BL2.TZ.SSCR.EVT1.1.bin、all00_padding.bin、E4412.TZ.SSCR.EVT1.1.bin 是由三星提供,在 CodeSign4SecureBoot_POP/ 目录下。
所以,执行 ./build_uboot.sh POP_1GDDR 前,需要把三星提供的目录 CodeSign4SecureBoot_POP 拷到 u-boot 目录 的上级目录下。
基本流程就是:
1、make itop_4412_android_config_pop_1GDDR 进行配置,
2、make -j4 编译生成 u-boot.bin,
3、cat E4412.S.BL1.SSCR.EVT1.1.bin E4412.BL2.TZ.SSCR.EVT1.1.bin all00_padding.bin u-boot.bin E4412.TZ.SSCR.EVT1.1.bin > u-boot-iTOP-4412.bin 拼成最终的 u-boot-iTOP-4412.bin
PS:build_uboot.sh 在原生的 u-boot 源代码上是没有的,原生的 u-boot 源代码,要自已 make xxxxxxxx_conf 再自己 make -j4,再自己 cat,当然,你可以自己仿照它写一个,方便编译。
1、make itop_4412_android_config_pop_1GDDR 进行配置
打开 Makefile,Makefile的源码比较长,我就不放了。
没有 Makefile 基础的同学们,请移步 《Makefile基础 - 让我欢喜让我忧》
搜一下:itop_4412_android_config_pop_1GDDR
itop_4412_android_config_pop_1GDDR: unconfig
@$(MKCONFIG) $(@:_config=) arm arm_cortexa9 smdkc210 samsung s5pc210 POP_1GDDR
@$(MKCONFIG) $(@:_config=) arm arm_cortexa9 smdkc210 samsung s5pc210 POP_1GDDR
MKCONFIG := $(SRCTREE)/mkconfig
$(@:_config=) 是把 itop_4412_android_config_pop_1GDDR中的 _config去掉,
所以,整个就变成了
mkconfig itop_4412_android_pop_1GDDR arm arm_cortexa9 smdkc210 samsung s5pc210 POP_1GDDR
mkconfig 是个什么东西?
mkconfig 也是个 shell 脚本,不熟悉 shell 脚本的同学,请移步《linux shell脚本 - 给男友的家务清单》。
#!/bin/sh -e
# Script to create header files and links to configure
# U-Boot for a specific board.
#
# Parameters: Target Architecture CPU Board [VENDOR] [SOC]
#
# (C) 2002-2006 DENX Software Engineering, Wolfgang Denk <wd@denx.de>
#
APPEND=no # Default: Create new config file
#BOARD_NAME="" # Name to print in make output
TARGETS=""
echo "CoreBoard is $7...... "
if [ "$7" = "SCP_1GDDR" ] || [ "$7" = "SCP_2GDDR" ] || [ "$7" = "POP_1GDDR" ] || [ "$7" = "POP_2GDDR" ]
then
BOARD_NAME="itop_4412_android"
echo "CoreBoard OS is android or linux...... "
elif [ "$7" = "SCP_1GDDR_Ubuntu" ] || [ "$7" = "SCP_2GDDR_Ubuntu" ] || [ "$7" = "POP_1GDDR_Ubuntu" ] || [ "$7" = "POP_2GDDR_Ubuntu" ]
then
BOARD_NAME="itop_4412_ubuntu"
echo "CoreBoard OS is Ubuntu...... "
else
echo "unknown coreboard type and os type......"
fi
while [ $# -gt 0 ] ; do
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
# -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
-t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;;
*) break ;;
esac
done
[ "${BOARD_NAME}" ] || BOARD_NAME="$1"
[ $# -lt 4 ] && exit 1
[ $# -gt 7 ] && exit 1
if [ "${ARCH}" -a "${ARCH}" != "$2" ]; then
echo "Failed: \$ARCH=${ARCH}, should be '$2' for ${BOARD_NAME}" 1>&2
exit 1
fi
echo "Configuring for ${BOARD_NAME} board..."
#
# Create link to architecture specific headers
#
if [ "$SRCTREE" != "$OBJTREE" ] ; then
mkdir -p ${OBJTREE}/include
mkdir -p ${OBJTREE}/include2
cd ${OBJTREE}/include2
rm -f asm
ln -s ${SRCTREE}/include/asm-$2 asm
LNPREFIX="../../include2/asm/"
cd ../include
rm -rf asm-$2
rm -f asm
mkdir asm-$2
ln -s asm-$2 asm
else
cd ./include
rm -f asm
ln -s asm-$2 asm
fi
rm -f asm-$2/arch
if [ -z "$6" -o "$6" = "NULL" ] ; then
ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
ln -s ${LNPREFIX}arch-$6 asm-$2/arch
fi
if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
#
# Create include file for Make
#
echo "ARCH = $2" > config.mk
echo "CPU = $3" >> config.mk
echo "BOARD = $4" >> config.mk
[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk
[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk
# Assign board directory to BOARDIR variable
if [ -z "$5" -o "$5" = "NULL" ] ; then
BOARDDIR=$4
else
BOARDDIR=$5/$4
fi
#add by dg for kinds of coreboard
if [ "$7" = "SCP_1GDDR" ] || [ "$7" = "SCP_2GDDR" ] || [ "$7" = "SCP_1GDDR_Ubuntu" ] || [ "$7" = "SCP_2GDDR_Ubuntu" ]
then
echo "CORE = SCP" >> config.mk
ln -sf ${SRCTREE}/board/samsung/smdkc210/lowlevel_init_SCP.S ${SRCTREE}/board/samsung/smdkc210/lowlevel_init.S
ln -sf ${SRCTREE}/cpu/arm_cortexa9/s5pc210/cpu_init_SCP.S ${SRCTREE}/cpu/arm_cortexa9/s5pc210/cpu_init.S
elif [ "$7" = "POP_1GDDR" ] || [ "$7" = "POP_2GDDR" ] || [ "$7" = "POP_1GDDR_Ubuntu" ] || [ "$7" = "POP_2GDDR_Ubuntu" ]
then
echo "CORE = POP" >> config.mk
ln -sf ${SRCTREE}/board/samsung/smdkc210/lowlevel_init_POP.S ${SRCTREE}/board/samsung/smdkc210/lowlevel_init.S
ln -sf ${SRCTREE}/cpu/arm_cortexa9/s5pc210/cpu_init_POP.S ${SRCTREE}/cpu/arm_cortexa9/s5pc210/cpu_init.S
else
echo "make config error,please use correct params......"
exit 0
fi
#
# Create board specific header file
#
if [ "$APPEND" = "yes" ] # Append to existing config file
then
echo >> config.h
else
> config.h # Create new config file
fi
echo "/* Automatically generated - do not edit */" >>config.h
for i in ${TARGETS} ; do
echo "#define CONFIG_MK_${i} 1" >>config.h ;
done
#add by dg for all itop4412 type boards
[ "$7" ] && [ "$7" != "NULL" ] && echo "#define CONFIG_$7" >> config.h
cat << EOF >> config.h
#define CONFIG_BOARDDIR board/$BOARDDIR
#include <config_defaults.h>
#include <configs/$BOARD_NAME.h>
#include <asm/config.h>
EOF
exit 0
它创建了一些编译所需的链接文件(类似于快捷方式,方便不同平台编译)、配置文件(如config.mk、config.h等),等等。
所以,make itop_4412_android_config_pop_1GDDR 的作用是配置编译所需要的文件和环境,为下一步编译做准备。
2、make -j4 编译生成 u-boot.bin
这个就是编译生成,它编译生成 u-boot.bin,但这不是我们最终烧录进板卡的 bootlaoder。
3、cat E4412.S.BL1.SSCR.EVT1.1.bin E4412.BL2.TZ.SSCR.EVT1.1.bin all00_padding.bin u-boot.bin E4412.TZ.SSCR.EVT1.1.bin > u-boot-iTOP-4412.bin
这句生成最终的 u-boot-iTOP-4412.bin 文件,是我们最终烧录进板卡的 bootloader。
基中,
4412.S.BL1.SSCR.EVT1.1.bin 大小 8k,是由三星提供的 BL1;
E4412.BL2.TZ.SSCR.EVT1.1.bin+all00_padding.bin,总共16K,是由三星提供的 BL2;
u-boot.bin 大小328k,是自个源码编译生成的,如果我们的源码不够328k,sdfuse_q/add_padding会自动补足(在Makefile中有一句@./sdfuse_q/add_padding),所以,u-boot.bin不管怎么编译,都是 328k;
至此,整个 u-boot 编译完成,生成的 u-boot-iTOP-4412.bin 可以直接写进 SD 卡里面。