u-boot分析(二) u-boot的编译及配置 mkconfig
刚开始接触u-boot总是存在这样的疑问,../include/configs/mini2440.h是如何关联到../board/mini2440.c中的?显然他们并没有在源码中有直接的包含关系。
编译u-boot时,输入
make mini2440_config
make
u-boot就被成功创建了,这都归功于Makefile与mkconfig
在u-boot的顶层文件夹中的Readme中,有如下描述:
If the system board that you have is not listed,then you will need
to port U-Boot to your hardware platform. To dothis, follow these
steps:
1. Add anew configuration option for your board to the toplevel "Makefile"and to the "MAKEALL" script, using the existing entries as examples.Note that here and at many other places boards and other names are listed inalphabetical sort order. Please keep this order.
2. Create anew directory to hold your board specific code. Add any files you need. In yourboard directory, you will need at least the "Makefile", a"<board>.c", "flash.c" and "u-boot.lds".
3. Create anew configuration file "include/configs/<board>.h" for yourboard
3. Ifyou're porting U-Boot to a new CPU, then also create a new directory to holdyour CPU specific code. Add any files you need.
4. Run"make <board>_config" with your new name.
5. Type"make", and you should get a working "u-boot.srec" file tobe installed on your target system.
6. Debugand solve any problems that might arise.[Of course, this last step is muchharder than it sounds.]
向u-boot源码树种添加自己的硬件平台需要做上述6条,以添加mini2440为例
第一向顶层Makefile中添加新的configuration option,按照已有的硬件平台为格式添加mini2440
mini2440_config : unconfig
@$(MKCONFIG)$(@:_config=) arm arm920t mini2440 NULL s3c24x0
第二在../board文件夹中新建合适的文件夹,用来存放新添加的板级文件:
新建文件夹mini2440,并添加mini2440.c,config.mk,lowlevel_init.S,Makefile,nand_read.c,flash.c
第三步创建新的配置文件"include/configs/mini2440.h"
第四步 make mini2440_config
第五步 make
最后debug
现在开始分析他们是如何建立起连接关系的
在顶层Makefile中可以看到如下代码
SRCTREE :=$(CURDIR)
TOPDIR :=$(SRCTREE)
export TOPDIRSRCTREE OBJTREE
MKCONFIG :=$(SRCTREE)/mkconfig
……
mini2440_config : unconfig
@$(MKCONFIG)$(@:_config=) arm arm920t mini2440 NULL s3c24x0
……
TOPDIR就是SRCTREE,也就是u-boot源码的顶层目录,则其中的MKCONFIG就是根目录下的mkconfig,$(@:_config=)的结果就是将“mini2440_config”中的“_config”去掉,结果为“mini2440”。所以“make mini2440_config”实际上就是执行如下命令:
./mkconfig mini2440 arm arm920t mini2440NULL s3c24x0
mkconfig是一个shell脚本,在mkconfig文件开头第6行给出了它的用法
06 # Parameters: Target Architecture CPUBoard [VENDOR] [SOC]
所以Makefile调用了它并给它传递了6个参数,分别是:【注】shell中用$n代表第n个参数
$1= mini2440
$2= arm
$3= arm920t
$4= mini2440
$5= NULL
$6= s3c24x0
现在分步骤分析mkconfig的作用
(1) 确定开发板的BOARD_NAME
01 APPEND=no # Default: Create new config file
02 BOARD_NAME="" # Name to print in make output
03 TARGETS=""
04 while [ $# -gt 0 ] ; do
05 case"$1" in
06 --)shift ; break ;;
07 -a)shift ; APPEND=yes ;;
08 -n)shift ; BOARD_NAME="${1%%_config}" ; shift ;;
09 -t)shift ; TARGETS="`echo $1 | sed 's:_: :g'` ${TARGETS}" ; shift ;;
10 *) break ;;
11 esac
12 done
[ "${BOARD_NAME}" ] ||BOARD_NAME="$1"
对于./mkconfigmini2440 arm arm920t mini2440 NULL s3c24x0这条命令没有”—“,”-a”等参数,所以4~12行没有做任何事情,第一第二行的变量保持
执行完12行BOARD_NAME==$1== mini2440
(2) 创建到开发板相关头文件的链接
略过mkconfig文件中的一些没有起作用的行
#
# Create link to architecture specificheaders
#
01 if [ "$SRCTREE" !="$OBJTREE" ] ; then
02 mkdir-p ${OBJTREE}/include
03 mkdir-p ${OBJTREE}/include2
04 cd${OBJTREE}/include2
05 rm-f asm
06 ln-s ${SRCTREE}/include/asm-$2 asm
07 LNPREFIX="../../include2/asm/"
08 cd../include
09 rm-rf asm-$2
10 rm-f asm
11 mkdirasm-$2
12 ln-s asm-$2 asm
13 else
14 cd./include
15 rm-f asm
16 ln-s asm-$2 asm
17 fi
第一行判断源代码目录和目标文件目录是否一样,是可以选择在其他目录下编译u-boot,这样可以令源代码目录保持干净,可以同时使用不同的配置进行编译,不过一般是在代码目录下进行编译,所以第1行条件不满足,跳转到else执行,进入include目录,删除asm文件(这是上一次配置时建立的链接文件),然后再次建立asm文件,并令它链接向asm-$2目录,即asm-arm。
继续看代码
01 rm -f asm-$2/arch
02
03 if [ -z "$6" -o "$6"= "NULL" ] ; then
04 ln-s ${LNPREFIX}arch-$3 asm-$2/arch
05 else
06 ln-s ${LNPREFIX}arch-$6 asm-$2/arch
07 fi
08
09 if [ "$2" = "arm" ]; then
10 rm-f asm-$2/proc
11 ln-s ${LNPREFIX}proc-armv asm-$2/proc
12 fi
第1行删除asm-$2/arch目录,即asm-arm/arch。
$6== s3c24x0,所以03行不满足执行06行,LNPREFIX为空,所以这个命令实际上就是:ln -s arch-$6asm-$2/arch,即:ln -sarch-s3c24x0 asm-arm/arch。第10、11行重新建立asm-arm/proc文件,并让它链接向proc-armv目录。
(3) 创建顶层Makefile包含的文件include/config.mk
01 #
02 # Create include file for Make
03 #
04 echo "ARCH = $2" > config.mk
05 echo "CPU = $3" >> config.mk
06 echo "BOARD = $4" >> config.mk
07
08 [ "$5" ] && ["$5" != "NULL" ] && echo "VENDOR = $5">> config.mk
09
10 [ "$6" ] && ["$6" != "NULL" ] && echo "SOC = $6" >> config.mk
对于./mkconfig mini2440arm arm920t mini2440 NULL s3c24x0命令,上面几行代码创建的config.mk文件内容如下:
ARCH = arm
CPU = arm920t
BOARD = mini2440
SOC = s3c24x0
(4) 创建开发板相关的头文件include/config.h。
01 #
02 # Create board specific header file
03 #
04 if [ "$APPEND" ="yes" ] # Append toexisting config file
05 then
06 echo>> config.h
07 else
08 >config.h # Create new configfile
09 fi
10 echo "/* Automatically generated -do not edit */" >>config.h
11
12 for i in ${TARGETS} ; do
13 echo"#define CONFIG_MK_${i} 1" >>config.h ;
14 done
15
16 cat << EOF >> config.h
17 #define CONFIG_BOARDDIR board/$BOARDDIR
18 #include <config_defaults.h>
19 #include <configs/$1.h>
20 #include <asm/config.h>
21 EOF
22 exit 0
前面说过,APPEND维持原值“no”,所以config.h被重新建立,它的内容如下:
/* Automatically generated - do not edit */
#include <configs/mini2440.h>"
这样mini2440就被间接包含了进来,现在再对照readme中的步骤,是不是豁然开朗了?
U-Boot还没有类似Linux一样的可视化配置界面(比如使用make menuconfig来配置),要手动修改配置文件include/config/<board_name>.h来裁减、设置U-Boot。
配置文件中有两类宏:
(1)一类是选项(Options),前缀为“CONFIG_”,它们用于选择CPU、SOC、开发板类型,设置系统时钟、选择设备驱动等。比如:
#define CONFIG_ARM920T1/* This is anARM920T Core*/
#defineCONFIG_S3C24101/* in a SAMSUNG S3C2410 SoC */
#define CONFIG_SMDK24101/* on a SAMSUNGSMDK2410 Board */
#define CONFIG_SYS_CLK_FREQ12000000/* theSMDK2410 has 12MHz input clock */
#define CONFIG_DRIVER_CS89001/* we have aCS8900 on-board */
(2)另一类是参数(Setting),前缀为“CFG_”,它们用于设置malloc缓冲池的大小、U-Boot的提示符、U-Boot下载文件时的默认加载地址、Flash的起始地址等。比如:
#define CFG_MALLOC_LEN(CFG_ENV_SIZE +128*1024)
#defineCFG_PROMPT"100ASK> "/*Monitor Command Prompt*/
#defineCFG_LOAD_ADDR0x33000000/* default loadaddress*/
#define PHYS_FLASH_10x00000000 /* FlashBank #1 */
从下面的编译、连接过程可知,U-Boot中几乎每个文件都被编译和连接,但是这些文件是否包含有效的代码,则由宏开关来设置。比如对于网卡驱动drivers/cs8900.c,它的格式为:
#include <common.h>/* 将包含配置文件include/config/<board_name>.h*/
……
#ifdef CONFIG_DRIVER_CS8900
/* 实际的代码 */
……
#endif/* CONFIG_DRIVER_CS8900 */
如果定义了宏CONFIG_DRIVER_CS8900,则文件中包含有效的代码;否则,文件被注释为空。
可以这样粗糙地认为,“CONFIG_”除了设置一些参数外,主要用来设置U-Boot的功能、选择使用文件中的哪一部分;而“CFG_”用来设置更细节的参数。