1234567890
分类: 嵌入式
2013-09-16 10:35:00
本文是针友善之臂公司出品的mini2440进行移植,其CPU不ARM920T架构的S3C2440,一片
64M Nand Flash (K9F1208),一片2M Nor Flash 更具体数据请参考开发板手册。
u-boot-1.1.6有几千个文件,不可能对每一个文件都了解得非常细致,我们只需要了解自己
工程所用到的相关文件即可,这也是一贯的做法。首先大概的看一下u-boot的文件结构,对其
有个大概的了解,最好的办法是查看顶层的Makdfile由其推出其文件间的依赖关系,这样对移
植有很大的帮助。
代码结构与功能
board——目标板相关文件,主要包含SDRAM、Flash驱动;
common——独立于处理器体系结构的通用代码,如内存大小探测与故障检测;
cpu——与处理器相关的文件,如mpc8xx子目录下含串口、网口、LCD驱动及中断初始化等文件;
driver——通用设备驱动,如CFI Flash驱动;
doc——U-Boot的说明文档;
examples——可在U-Boot下运行的示例程序;如helloworld.c,timer.c;
include——U-Boot头文件,configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件;
lib_xxx——处理器体系相关的文件,如lib—ppc,lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件;
net——与网络功能相关的文件目录,如bootp、nfs、tftp;
post——上电自检文件目录,尚有待于进一步完善;
rtc——RTC驱动程序;
tools——用于创建U-Boot S-RECORD和BIN镜像文件的工具
//********************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
几个重要的文件分析:
u-boot-1.1.5/Makefile
u-boot-1.1.5/mkconfig
u-boot-1.1.5/config.mk
u-boot根目录下的Makefile文件(u-boot-1.1.5/Makefile)它负责配置u-boot的编译方式,具体说来包括:使用何
种指令集,需包含哪些接口驱动、库等。Makefile的内容从上到下分别是:分定义编译环境:使用何种编译器、编译方式、
目标文件的生成及它们最终镜像中的链接次序等。Mkconfig和config.mk在接下来的分析中会涉及到。
以SMDK2410为例
在编译U-BOOT之前,先要执行
# make smdk2410_config
smdk2410_config是Makefile的一个目标,定义如下:
smdk2410_config: unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
其中,unconfig定义如下:
unconfig:
@rm -f $(obj)include/config.h $(obj)include/config.mk \
$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
所以可以看到,当执行make smdk2410_config时,那么make就会先执行unconfig,由unconfig定义可得该命令是
执行清理上一次执行make *_config所生成的头文件与和Makefile包含的相关文件,主要是include/config.h include/config.mk
board/*/config.tmp board/*/*/config.tmp (此处的*为开发板的名称,例如smdk2410)
注:如果命令行中指定了编译目录,则要到自己指定的编译目录中去删除这几个文件。
接着就是执行@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0其中在这里第一个@是GNU一种“所有匹配模式”规则,那么
$(MKCONFIG)相当于./mkconfig
在这里特别注意一下$(MKCONFIG)是指引用变量MKCONFIG,而在文件开头有对MKCONFIG的定义
MKCONFIG :=$(SRCTREE)/mkconfig
而变量SRCTREE定义在前面指定为
SRCTREE :=$(CURDIR)
再找到变量CURDIR的定义
在Makfile里找不到其定义,因为它是GNU make的环境变量不需要我们定义
此变量代表make的工作目录当使用“-C”选项进入一个子目录后,此变量将
被重新赋值。总之,如果在Makefile中没有对此变量进行显式的赋值操作,那
么它代表make的工作目录。我们也可以在Makefile为这个变量赋一个新的值。
此时这变量将不再代表make的工作目录。
例如当在目录/下
输入 make –C /usr/u-boot-1.1.6/ smdk2410_config
那么CURDIR的值就是/usr/u-boot-1.1.6
而当我直接在目录/usr/u-boot-1.1.6下
输入 make smdk2410_config
那么CURDIV的值就是.
由于我们直接在源代码目录下执行make一步步的向前推那就是$(MKCONFIG)相当于./mkconfig
接着下来就到命令行的第二部分$(@:_config=)在这里更要特别的注意了,这里不是变量的引用,在Makefile文件里根本就找不到”变量,所以不能理解为变量,它是GNU make的一个函数,其实这是一个简化的函数 $(VAR:PATTERN=REPLACEMENT)
在GNU中有函数
$(patsubst
函数名称:模式替换函数—patsubst
函数功能:查找
是否符合模式< pattern>,如果匹配的话,则以
里,
中也包含“%”,那么,
的那个“%”所代表的字串。(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)
返 回 值:替换后的新字符串
函数说明:参数“TEXT”单词之间的多个空格在处理时被合并为一个空格,并忽略前导和结尾空格
例如:
$(patsubst %.c,%.o,x.c.c bar.c)
把字串“x.c.c bar.c”中以.c结尾的单词替换成以.o结尾的字符。函数的返回结果是“x.c.o bar.o”
而$(var:
所以在$(@:_config=)中就是$(smdk2410_config:_config=)
转为$(patsubst _config,,smdk2410_config)
依定义为把字符串“smdk2410_config”的字符串“_config”用空代替,等于是去除“_config”
返回值为“smdk2410”
到此为止先看一下“@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0”变成什么样了,下面就是真实的命令了
./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0
此命令是执行当前目录下mkconfig脚本,并传入参数,在这里有六个参数,分别为smdk2410 arm arm920t smdk2410 NULL s3c24x0
而这六个参数分别代表什么含义就要到mkconfig里看一看了
使用vim查看 vim mkconfig
//****************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////
下面着重分析一下mkconfig:
(一)首先mkconfig第一行就是#!/bin/sh –e它的用途就是指出本脚本是用的哪种shell写的,执行时系统应该用哪种
shell来解释执行它,显然这里是用目录下/bin/sh 的shell来解释这个脚本。其实每一个文件我应该先认真读一下前面的注解信息
这一句就简单明了说出该脚的作用是“为一个特定的开发板创建一些相关的头文件和相关配置链接”
下一句 #Parameters: Target Architecture CPU Board [VENDOR] [SOC]说明了各种参数的意义
Target: 宿主机平台
Architecture: 定义芯片架构(如MIPS、POWERPC、ARM等)
CPU: 定义芯片指令集版本(如ARM7、ARM9、ARM11等)
Board: 芯片厂商,它细分为两类
[VENDOR]: 按厂商划分(如AT9200、S3C44B0等)
[SOC]: 按SOC类型(如S3C2440、S3C2410等)
对于#make smdk2410_config命令,由上面分析可以传入参数为
smdk2410 arm arm920t smdk2410 NULL s3c24x0
与Target Architecture CPU Board [WENDOR] [SOC]
一一对应[VENDOR]为空,即是NULL 同时注意到上面六个参数与下面的
$1 $2 $3 $4 $5 $6也是一一对应的关系
//****************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////
(二)接着下来分析mkconfig中的各个语句
下面的语中
11 APPEND=no # Default: Create new config file
默认情况下创建一个新的config文件
12 BOARD_NAME="" # Name to print in make output
显示输出的开发板名字,此时为空
13
14 while [ $# -gt 0 ] ; do # [ ]是Bash里的一个测试命令,在这里是如果参
# 数变量个数大于(-gt)零则执行do后的语句
注:在Bash里“$#”是传到脚本里的位置参数的个数
15 case "$1" in # 第一个参数为下列值中的一个
16 --) shift ; break ;; # 如果$1为“--”时,所有参数向左移一位,
# 即把原$1丢弃,原$2补上$1<-$2<-$3<-$4<-$5<-$6
# 但要注意的是$0即脚本名,保持不变,只
# 是把原$1丢弃,接着跳出
17 -a) shift ; APPEND=yes ;; # 如果“$”1为“-a”则APPEND的值
# 由no改成yes 接着跳出(这里;;相当于break;)
18 -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
# 如果“$1”为“-n”则BOARD_NAME变
# 为“$1”(注意此时的$1已不是刚传入的
# “-n”)去掉从右往左算起最后一个“_config”
# 字符串剩下的字符串,接着所有参数再
# 左移一位,然后跳出循环与case语句
注:在Bash里${1%%_config}是一种字符串操作,其标准
形式:${string%%substring} 从$string 的右边截掉最后一个匹配的$substring
19 *) break ;; # 如果为其他值则直接跳出
20 esac
21 done
22
23 [ "${BOARD_NAME}" ] || BOARD_NAME="$1"
# 这里主要是给BOARD_NAME 赋值,当为空时
# 赋值为“$1”当不为空这保持不变
24
25 [ $# -lt 4 ] && exit 1 # 如果位置参数的个数小于4则退出
26 [ $# -gt 6 ] && exit 1 # 如果位置参数的个数大于6则退出
27
28 echo "Configuring for ${BOARD_NAME} board..."
# 在终端上显示Configuring for ${BOARD_NAME} board...
现在回头看一下,总结到目前为止脚本到底做了哪些事情。主要是根据传入的参数做一些简单的配置,对
一些变量进行设置,使之可以为后面所用,让我看下两个例子:
当输入为make smdk2410_config时
在u-boot-1.1.6的根目录下输入make smdk2410_config由前面对Makefile粗浅认识
相当于执行了./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0 此时传入的
位置参数
$1 = smdk2410
$2 = arm
$3 = arm920t
$4 = smdk2410
$5 = NULL(为空)
$6 = s3c24x0
接着进入while部分,执行while [ $# -gt 0 ] ($#为6,大于0)
进入case执行 *) break ;; (因为$1为smdk2410)
然后执行[ "${BOARD_NAME}" ] || BOARD_NAME="$1" (此时BOARD_NAME= smdk2410)
跳过[ $# -lt 4 ] && exit 1
跳过[ $# -gt 6 ] && exit 1
紧接执行echo "Configuring for ${BOARD_NAME} board..."
(在屏幕上可以看Configuring for ${BOARD_NAME} board.. )
当输入为 make cpci5200_config时
相当于执行了./mkconfig -a cpci5200 ppc mpc5xxx cpci5200 esd此时传入的
位置参数
$1 = -a
$2 = cpci5200
$3 = ppc
$4 = mpc5xxx
$5 = cpci5200
$6 = esd
当执行完echo "Configuring for ${BOARD_NAME} board..."
此时
BOARD_NAME = cpci5200
APPEND=yes
//****************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////
(三)接着下来分析mkconfig里的下一部分代码
由# Create link to architecture specific headers可知这一部分是
“为指定的芯片架构创建文件链接”
33 if [ "$SRCTREE" != "$OBJTREE" ] ; then # 测试$SRCTREE与$OBJTREE不相等依情况执行不同分支
34 mkdir -p ${OBJTREE}/include # 如果不等,则创建目录文件夹${OBJTREE}/include
35 mkdir -p ${OBJTREE}/include2 # 创建目录文件夹${OBJTREE}/include2
36 cd ${OBJTREE}/include2 # 进入目录文件夹${OBJTREE}/include2
37 rm -f asm # 删除当前目录下的asm
38 ln -s ${SRCTREE}/include/asm-$2 asm # 建立${SRCTREE}/include/asm-$2文件的符号链接,并命名为asm
39 LNPREFIX="../../include2/asm/" # 给LNPREFIX赋值为../../include2/asm/
40 cd ../include # 进入目录${OBJTREE}/include
41 rm -rf asm-$2 # 删除目录asm-$2及下所有东西
42 rm -f asm # 删除asm
43 mkdir asm-$2 # 创建目录asm-$2(当前在目录${OBJTREE}/include/)
44 ln -s asm-$2 asm # 建立asm-$2文件的符号链接,并命名为asm
45 else
46 cd ./include # 如果$SRCTREE与$OBJTREE相等,则进入./include
47 rm -f asm # 删除asrm
48 ln -s asm-$2 asm # 建立asm-$2文件的符号链接,并命名为asm(在当前目录下有asm)
49 fi
50
51 rm -f asm-$2/arch # 删除目录include/ asm-$2/下的arch
52
53 if [ -z "$6" -o "$6" = "NULL" ] ; then # 如果$6的长度为0或为NULL则执行then分支
# 这里说明一下“-z 字符串为"null".就是长度为0”
# “-o 逻辑或”
54 ln -s ${LNPREFIX}arch-$3 asm-$2/arch # 建立${LNPREFIX}arch-$3文件的符号链接,并命名为asm-$2/arch
55 else
56 ln -s ${LNPREFIX}arch-$6 asm-$2/arch # 建立${LNPREFIX}arch-$6文件的符号链接,并命名为asm-$2/arch
57 fi
58
59 if [ "$2" = "arm" ] ; then # 如果第二个参数为arm则执行then分支
60 rm -f asm-$2/proc # 删除目录asm-$2/proc(当前所在目录为${OBJTREE}/include/)
61 ln -s ${LNPREFIX}proc-armv asm-$2/proc # 建立${LNPREFIX}proc-armv文件
# 的符号链接,并命名为asm-$2/ proc
62 fi
63
64 #
对于make smdk2410_config
执行cd ./include (当前目录为/usr/u-boot-1.1.6/include)
rm -f asm (别忘了是在目录/usr/u-boot-1.1.6/include下的asm)
ln -s asm-$2 asm ($2为arm)
rm -f asm-$2/arch ($2为arm)
ln -s ${LNPREFIX}arch-$6 asm-$2/arch (LNPREFIX为../../include/asm/)
rm -f asm-$2/proc (当前目录为/usr/u-boot-1.1.6/include)
ln -s ${LNPREFIX}proc-armv asm-$2/proc (LNPREFIX为../../include/asm/,当前目录为/usr/u-boot-1.1.6/include)
结果如下
//****************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////
(四)文件链接先告一段落,接着往下看另一部分
由# Create include file for Make可知这里为Make创建一些相关的包含文件
67 echo "ARCH = $2" > config.mk # 将ARCH = $2重定向到文件config.mk
# 如果没有这个文件则创建,有这个文
# 件就覆盖原来的文件内容,config.mk
# 在当前目录下
68 echo "CPU = $3" >> config.mk # 重定向CPU = $3到文件config.mk,如
# 果没有则创建一个新的,并将信息输
# 入;如果存在,就在原文件后面追加
# 上要输入的信息。
69 echo "BOARD = $4" >> config.mk
70
71 [ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk
72
73 [ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk
上面的依照分析即行
注:
在bash里有> >>是IO重定向1 COMMAND_OUTPUT >
2 # 重定向stdout 到一个文件.
3 # 如果没有这个文件就创建, 否则就覆盖.
18 COMMAND_OUTPUT >>
19 # 重定向stdout 到一个文件.
20 # 如果文件不存在, 那么就创建它, 如果存在, 那么就追加到文件后边.
所以这一部分就是将
ARCH = arm
CPU = arm920t
BOARD = smdk2410
SOC = s3c24x0
重定向到文件config.mk,即将其输入到config.mk,这时在../include目录下生成一个文件config.mk
如下图所示:
打印其中的信息:
这文件就是记录一些开发板的信息,被Makefile所用,打开Makefile在前面那里可以找到相关的信息:
从这里我们可以看到,把./include下的文件config.mk包含进Makefile里
然后声明一些环境变量 ARCH CPU BOARD VENDOR SOC
注:
当一个变量使用“export”进行声明后,变量和它的值将被加入到当前工作的
环境变量中,以后在make执行的所有规则的命令都可以使用这个变量。而当没
有使用指示符“export”对任何变量进行声明的情况下,上层make只将那些已经
初始化的环境变量(在执行make之前已经存在的环境变量)和使用命令行指定
的变量(如命令“make CFLAGS +=-g”或者“make –e CFLAGS +=-g”)传递给子
make程序,在这里主要是传递给MAKEALL
//****************************************************************************************************//
////////////////////////////////////////////////////////////////////////////////////////////////////////
(五)接下就要分析mkconfig最后的一部分了,很快就把mkconfig文件分析完:
这一部分里主要的工作是创建对特定开以板的头文件
从上面可以看到相应的结果
//******************************************************************************************************//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
到此为止就反mkconfig文件就全部分析完毕,也就是对于Makdfile里的smdk2410_config作用分析也完成了,显然这
样有点乱,因为在这过程中穿插了许多相关知识这些主要参考了《GNU中文手册》《GCC中文手册》《高级Bash 脚本编程指南》
现在认我们再从重头总结一下命令执行的过程以及相关的结果,以smdk2410开发板为例:
① 在终端下输入make smdk2410_config
|
② 进入Makefile执行相关的命令即
smdk2410_config: unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
|
③ 先执行uconfig删除上次生成的相关文件
|
④ 紧接执行./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0
此时进入mkconfig文件里执行相关语句
|
⑤ 变量APPEND=no BOARD_NAME=smdk24410
在终端上显示Configuring for ${BOARD_NAME} board...
|
⑥ 在目录./include下创建文件链接
asm-arm -> asm
../include/asm/arch-s3c24x0 -> asm-arm/arch
../include/asm/proc-armv -> asm-arm/proc
|
⑦ 在./include/config.mk文件里写入
ARCH = arm
CPU = arm920t
BOARD = smdk2410
SOC = s3c24x0
|
⑧ 接下来就在./include/config.h文件里写入
/* Automatically generated - do not edit */
#include
|
⑨完成./mkconfig
附件:
文件:
U-boot1.1.6移植之Makefile分析(一).pdf
大小:
402KB
下载:
下载