config的流程
uboot的顶层配置主要依靠 Makefile mkconfig boards.cfg以及include目录下面的config.mk config.h几个工程文件管理进行选择。
uboot的配置就是通过键入相应的命令将相应的Makfile变量赋值,通过你的配置,Makefile相应的变量就知道编译哪个平台下的哪个cpu的哪个版本的开发板。注意:不同版本的uboot的配置命令可能是不同的,拿到源码包看README是个很好的习惯,比如uboot-2013-01的配置命令是下面这个样子的,但uboot-2016.10的配置命令就不是这个,感兴趣的可以查一下。:
在uboot-2013-01中,顶层目录下的boards.cfs文件中查看它支持的开发板和相应的信息,这个文件就像一个全局的"字典",后续的编译过程需要根据配置名检索到相应的信息,所以不要随意修改。下面这个就是字典的样子
config的分析
首先,当我们"make tda2x_fvcm_sdboot_config"的时候,uboot会生成makefile里面的一个叫tda2x_fvcm_sdboot_config的目标。根据Makefile文件的命令,我们就可以找到下面这一行命令。
%是Makefile中的通配符,表示任意字符串,所以我们的tda2x_fvcm_sdboot_config就会与之相匹配,这个目标的依赖于
outputmakefile
。
"MKCONFIG"就是顶层目录下的mkconfig脚本,而"$(@:_config=)"
就是去除目标中的"_config"串,所以实际上就是去到顶层目录下执行"$mkconfig -A tda2x_fvcm_sdboot"。
在mkconfig中
我们传入的参数会导致脚本执行这个if里面的内容,用扩展正则表达式去顶层目录下的boads.cfg文件中提取含有tda2x_fvcm_sdboot相应的行到line
变量中(如图),并把line设置为新的参数列表。取得了这个参数字符串,mkconfig就可以把相应的头文件,链接和全局变量准备好。
shell中的 line= Active arm armv7 omap5 ti tda2x_fvcm tda2x_fvcm_sdboot tda2x_fvcm:CONS_INDEX=1,SD_BOOT,ENV_IS_IN_MMC
一共8个参数
$1=Active
$2=arm
$3=armv7
$4=omap5
$5=ti
$6=dra7xx_fvcm
$7=dra7xx_fvcm_sdboot
$8=dra7xx_fcvm:CONS_INDEX=1,SD_BOOT,ENV_IS_IN_MMC
根据boards.cfg,这几个参数分别是:TARGET,ARCH,CPU,Board name,Vendor,SoC,OptionsSo.
首先shell会看check参数,是否有--,-a,-n,-t, 是否比7小比8大。
while [ $# -gt 0 ] ; do
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${7%_config}" ; shift ;;
-t) shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;;
*) break ;;
esac
done
[ $# -lt 7 ] && exit 1
[ $# -gt 8 ] && exit 1
然后,这部分的shell脚本就是把之前在cfg文件中找到的那一行信息的内容分段并赋值给开头的arch、cpu、board等变量,显然,这些变量就是我们需要的板级信息,uboot在编译的时候对于我们找到相应的目录,相应的文件至关重要。这些信息,会在mkconfig的之后写入到相应的配置文件中:、,如下会将各种信息进行解析,
# Strip all options and/or _config suffixes
CONFIG_NAME="${7%_config}"
[ "${BOARD_NAME}" ] || BOARD_NAME="${7%_config}"
arch="$2"
cpu=`echo $3 | awk 'BEGIN {FS = ":"} ; {print $1}'`
spl_cpu=`echo $3 | awk 'BEGIN {FS = ":"} ; {print $2}'`
if [ "$cpu" = "-" ] ; then
cpu=
fi
[ "$6" != "-" ] && board="$6"
[ "$5" != "-" ] && vendor="$5"
[ "$4" != "-" ] && soc="$4"
[ $# -gt 7 ] && [ "$8" != "-" ] && {
# check if we have a board config name in the options field
# the options field mave have a board config name and a list
# of options, both separated by a colon (':'); the options are
# separated by commas (',').
#
# Check for board name
tmp="${8%:*}"
if [ "$tmp" ] ; then
CONFIG_NAME="$tmp"
fi
# Check if we only have a colon...
if [ "${tmp}" != "$8" ] ; then
options=${8#*:}
TARGETS="`echo ${options} | sed 's:,: :g'` ${TARGETS}"
fi
}
if [ "${ARCH}" -a "${ARCH}" != "${arch}" ]; then
echo "Failed: \$ARCH=${ARCH}, should be '${arch}' for ${BOARD_NAME}" 1>&2
exit 1
fi
#
# Test above needed aarch64, now we need arm
#
if [ "${arch}" = "aarch64" ]; then
arch="arm"
fi
if [ "$options" ] ; then
echo "Configuring for ${BOARD_NAME} - Board: ${CONFIG_NAME}, Options: ${options}"
else
echo "Configuring for ${BOARD_NAME} board..."
fi
下面会创建include目录,并将获取到的架构(arch=armv7)这个里面的相关路径进行赋值给环境变量,并且进入到创建的include目录中,创建asm目录,将asm中的arch目录删掉。然后重新进行soc(ti)以及选择的cpu(dra7xx_fvcm)文件进行软连接。
#
# Create link to architecture specific headers
#
if [ -n "$KBUILD_SRC" ] ; then
mkdir -p ${objtree}/include
LNPREFIX=${srctree}/arch/${arch}/include/asm/
cd ${objtree}/include
mkdir -p asm
else
cd arch/${arch}/include
fi
rm -f asm/arch
if [ "${soc}" ] ; then
ln -s ${LNPREFIX}arch-${soc} asm/arch
elif [ "${cpu}" ] ; then
ln -s ${LNPREFIX}arch-${cpu} asm/arch
fi
if [ -z "$KBUILD_SRC" ] ; then
cd ${srctree}/include
fi
软连接机制是为了更好的进行管理,uboot永远只会去找同一个目录的文件,它的名字始终是一样的,不会因为cpu或者soc的不同而改变。
下面的shell脚本的作用是创建一个make文件,保存当前选择的芯片等信息。
#
# Create include file for Make
#
( echo "ARCH = ${arch}"
if [ ! -z "$spl_cpu" ] ; then
echo 'ifeq ($(CONFIG_SPL_BUILD),y)'
echo "CPU = ${spl_cpu}"
echo "else"
echo "CPU = ${cpu}"
echo "endif"
else
echo "CPU = ${cpu}"
fi
echo "BOARD = ${board}"
[ "${vendor}" ] && echo "VENDOR = ${vendor}"
[ "${soc}" ] && echo "SOC = ${soc}"
exit 0 ) > config.mk
根据上面的shell脚本会在include/config.mk生成如下的文件信息:
除了生成"include/config.mk",mkconfig还根据如下的shell命令生成"include/config.h"文件。
#
# 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
i="`echo ${i} | sed '/=/ {s/=/ /;q; } ; { s/$/ 1/; }'`"
echo "#define CONFIG_${i}" >>config.h ;
done
echo "#define CONFIG_SYS_ARCH \"${arch}\"" >> config.h
echo "#define CONFIG_SYS_CPU \"${cpu}\"" >> config.h
echo "#define CONFIG_SYS_BOARD \"${board}\"" >> config.h
[ "${vendor}" ] && echo "#define CONFIG_SYS_VENDOR \"${vendor}\"" >> config.h
[ "${soc}" ] && echo "#define CONFIG_SYS_SOC \"${soc}\"" >> config.h
[ "${board}" ] && echo "#define CONFIG_BOARDDIR board/$BOARDDIR" >> config.h
cat << EOF >> config.h
#include <config_cmd_defaults.h>
#include <config_defaults.h>
#include <configs/${CONFIG_NAME}.h>
#include <asm/config.h>
#include <config_fallbacks.h>
#include <config_uncmd_spl.h>
EOF
exit 0
它生成的"include/config.h"最终是长成这个样子的:
有了这两个文件,当我们再执行"$make"的时候就可以找到相应的文件了。